Skip to content

使用 Delegate 实现 APM(异步委托编程模型)

🏷️ C#

使用 delegateBeginInvokeEndInvoke 实现异步;

使用 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;
        }
    }
}

参考