[转]通用异步线程调用模式--通知线程
目的:对于以交互式的用户界面而言,假如要调用长时间运行的操作,那么可以使用以下模式让你的调用更方便。
问题:某个用户界面必须多次启动某个操作,开发人员希望将其从该接口的操作中分开。这里面可能有很多的理由,但最普遍的情形是多个操作需要被立即执行,或某个操作潜在地占用过多的时间,超过了用户所期望的等待响应时间。某写操作的完成总是要占用时间,在等待某个操作护照或者多个操作在后台执行时,用户界面应该允许用户继续做其他事情。对于web上的操作,现在流行的AJAX热得一塌糊涂,通过异步调用来获取服务器端信息并更新客户端。对于winform来说,当然也可以进行异步调用了。本文试图提供一个稍微通用一点的解决方法。
适用性:
在下列情况下可以使用:
采用胖客户端,WinForm实现。
操作被预期是长期的或者占用时间比较长的
多个操作必须立即被处理执行的
主要包括:
public delegate void CompleteEvent<T>(T t); //采用泛型委托,操作的结果被传递给调用方。
public delegate void ExceptionEvent(Exception ExceptionThrown); //异常将被传递给调用方
public NotifyingThreadManager<T> //通知线程管理
NotifyingThreadManager<T> 中
public void ExecuteAsync(System.Windows.Forms.Control ControlToNotify, CompleteEvent<T> NotificationDelegate, ExceptionEvent ExceptionDelegate) 的目标就是存储需要用来通知的信息和启动封装线程的执行。我们需要知道将要同步的控件以及用来处理结果的两个委托。
线程的主要工作在 protected void DoExecution()中完成,可以进行相应的修改以适应实际操作。
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5namespace com.tttick.NotifyingThreadManager
6{
7 public delegate void CompleteEvent<T>(T t);
8 public delegate void ExceptionEvent(Exception ExceptionThrown);
9 public class NotifyingThreadManager<T>
10 {
11 System.Windows.Forms.Control mControlToNotify;
12 CompleteEvent<T> mFactoringComplete;
13 ExceptionEvent mFactoringErrored;
14 Thread mExecution;
15 T t;
16 public NotifyingThreadManager(T t)
17 {
18 this.t = t;
19 }
20 public void ExecuteAsync(System.Windows.Forms.Control ControlToNotify, CompleteEvent<T> NotificationDelegate, ExceptionEvent ExceptionDelegate)
21 {
22 mControlToNotify = ControlToNotify;
23 mFactoringComplete = NotificationDelegate;
24 mFactoringErrored = ExceptionDelegate;
25 ThreadStart startThread = new ThreadStart(DoExecution);
26 mExecution = new Thread(startThread);
27 mExecution.Start();
28 }
29 protected void DoExecution()
30 {
31 object[] paramArray = new object[1];
32 try
33 {
34 //此处进行一个长时间的操作,请灵活使用
35 Thread.Sleep(10000);
36 paramArray[0]=t;
37 mControlToNotify.BeginInvoke(mFactoringComplete,paramArray);
38 }
39 catch (Exception ex)
40 {
41 paramArray[0] = ex;
42 mControlToNotify.BeginInvoke(mFactoringErrored, paramArray);
43 }
44 }
45
46 }
47}
调用操作如下
2 {
3 NotifyingThreadManager<string> f = new NotifyingThreadManager<string>("gadfg");
4 f.ExecuteAsync(this.button1, new CompleteEvent<string>(FactoringComplete), new ExceptionEvent(FactoringErrored));
5 }
6void FactoringComplete(string Result)
7 {
8 this.button1.Text+= Result;
9 }
10 void FactoringErrored( Exception ExceptionThrown)
11 {
12 this.button1.Text = ExceptionThrown.Message;
13 }
通过异步调用线程,更改按钮的文字显示。
对于构造函数的参数,还有线程的执行,只需要进行相应的修改即可满足要实际要求。
PS:本文部分内容参考<.NET模式>一书