使用 Delegate 实现 APM(异步委托编程模型)
🏷️ C#
使用 delegate
的 BeginInvoke
和 EndInvoke
实现异步;
使用 SynchronizationContext
实现跨线程访问控件;
示例代码
cs
using System;
using System.IO;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace APMSampleUseDelegate
{
public partial class MainForm : Form
{
private delegate void AsyncMethodCaller(string url);
SynchronizationContext sc;
public MainForm()
{
InitializeComponent();
txtUrl.Text = "http://www.baidu.com/";
}
private void btnDownload_Click(object sender, EventArgs e)
{
btnDownload.Enabled = false;
if (txtUrl.Text == string.Empty)
{
MessageBox.Show("Please input valid download file url");
btnDownload.Enabled = true;
return;
}
txtUrlHtml.Text = string.Empty;
AsyncMethodCaller caller = new AsyncMethodCaller(DownloadHtml);
caller.BeginInvoke(txtUrl.Text, GetResult, null);
sc = SynchronizationContext.Current;
}
private void DownloadHtml(string url)
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
Stream responseStream = response.GetResponseStream();
byte bufferRead = new byte[1000];
int pageSize = responseStream.Read(bufferRead, 0, bufferRead.Length);
while (pageSize > 0)
{
sc.Post(ShowPageHtml, Encoding.UTF8.GetString(bufferRead));
bufferRead = new byte[1000];
pageSize = responseStream.Read(bufferRead, 0, bufferRead.Length);
//Thread.Sleep(300);
}
}
// 异步操作完成时执行的方法
private void GetResult(IAsyncResult ar)
{
AsyncMethodCaller caller = (ar as AsyncResult).AsyncDelegate as AsyncMethodCaller;
// 调用 EndInvoke 去等待异步调用完成并且获得返回值
// 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成
caller.EndInvoke(ar);
// 通过获得 GUI 线程的同步上下文的派生对象,
// 然后调用 Post 方法来使更新 GUI 操作方法由 GUI 线程去执行
sc.Post(ResetBtnState, null);
}
private void ShowPageHtml(object result)
{
txtUrlHtml.Text += result.ToString();
}
private void ResetBtnState(object state)
{
btnDownload.Enabled = true;
}
}
}