/*
* MSDN Magazine May 2004中Basic Instincts:Updating the UI from a Secondary Thread一文的VC#实现
*
* 原文链接:
* 译文链接:
* 原作者:Ted Pattison
* VC#实现者:Abbey
*
* 原文的程序是用VB.NET写成的,有感于部分朋友对VB.NET并不熟悉(其实我也不懂VB,呵呵),而我也用VC#.NET
* 于是便有了用VC#.NET重写这个程序的想法。在重写的过程中,我加入了一些重要的注释和自己的理解
* 希望对各位的理解能有所帮助
*
* 这个程序的执行流程:
* @ 点击窗体上的“获取客户名单”按钮buttonGetCustomer,触发其单击消息处理函数buttonExit_Click()
* @ 在buttonExit_Click()中调用UpdateUI()更新UI,然后用准备好的GetCustomers()的委托进行异步调用,
* 并挂上回调方法MyCallback()
* @ 然后GetCustomers()开始与主线程一起执行,当它执行完之后调用MyCallback()
* @ 在MyCallback()内部,又用EndInvoke()取回结果,之后调用UpdateUI()实现UI更新
*
*
* 版权声明:未经作者同意,禁止以任何形式进行转载
*/
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading; //需要添加对这个命名空间的引用,才能使用Thread.Sleep()
namespace UpdateUI
{
public class MainForm : System.Windows.Forms.Form
{
private System.Windows.Forms.Button buttonGetCustomer;
private System.Windows.Forms.ListBox listBoxCustomer;
private System.Windows.Forms.Button buttonExit;
private System.Windows.Forms.StatusBar statusBar;
private System.ComponentModel.Container components = null;
//为了能使用BeginInvoke(),需要声明一个GetCustomers对应的委托类型GetListMethod
public delegate string[] GetListMethod();
private GetListMethod GetCustomersHandler;
//为了能在BeginInvoke()完成后自动调用一个回调方法,需要声明一个该方法的委托变量
private AsyncCallback CallbackHandler;
public MainForm()
{
InitializeComponent();
//把之后要用的两个委托准备好
GetCustomersHandler = new GetListMethod(GetCustomers);
CallbackHandler = new AsyncCallback(MyCallback);
//注意,如果我们要在StatusBar上使用Panel就还需要下面这样的步骤
//设置StatusBar的ShowPanels为true
//添加一个StatusBarPanel后才能真正使用
//statusBar.ShowPanels = true;
//StatusBarPanel Panel = new StatusBarPanel();
//statusBar.Panels.Add(Panel);
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
private void InitializeComponent()
{
this.buttonGetCustomer = new System.Windows.Forms.Button();
this.listBoxCustomer = new System.Windows.Forms.ListBox();
this.buttonExit = new System.Windows.Forms.Button();
this.statusBar = new System.Windows.Forms.StatusBar();
this.SuspendLayout();
//
// buttonGetCustomer
//
this.buttonGetCustomer.Location = new System.Drawing.Point(84, 24);
this.buttonGetCustomer.Name = "buttonGetCustomer";
this.buttonGetCustomer.Size = new System.Drawing.Size(120, 23);
this.buttonGetCustomer.TabIndex = 0;
this.buttonGetCustomer.Text = "获取客户名单(&G)";
this.buttonGetCustomer.Click += new System.EventHandler(this.buttonGetCustomer_Click);
//
// listBoxCustomer
//
this.listBoxCustomer.ItemHeight = 12;
this.listBoxCustomer.Location = new System.Drawing.Point(28, 71);
this.listBoxCustomer.Name = "listBoxCustomer";
this.listBoxCustomer.Size = new System.Drawing.Size(233, 88);
this.listBoxCustomer.TabIndex = 1;
//
// buttonExit
//
this.buttonExit.Location = new System.Drawing.Point(107, 192);
this.buttonExit.Name = "buttonExit";
this.buttonExit.TabIndex = 2;
this.buttonExit.Text = "退出(&E)";
this.buttonExit.Click += new System.EventHandler(this.buttonExit_Click);
//
// statusBar
//
this.statusBar.Location = new System.Drawing.Point(0, 240);
this.statusBar.Name = "statusBar";
this.statusBar.Size = new System.Drawing.Size(288, 22);
this.statusBar.TabIndex = 3;
this.statusBar.Text = "准备";
//
// MainForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(288, 262);
this.Controls.Add(this.statusBar);
this.Controls.Add(this.buttonExit);
this.Controls.Add(this.listBoxCustomer);
this.Controls.Add(this.buttonGetCustomer);
this.Name = "MainForm";
this.Text = "从辅助线程更新UI的C#实现";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
private void buttonExit_Click(object sender, System.EventArgs e)
{
Close();
}
//关于Delegate.BeginInvoke()方法的说明:
//返回值:IAsyncResult类型,表明异步操作的状态
//参数表第一部分是该委托类型的参数表
//第二部分包括一个委托方法执行完毕后自动调用的回调方法,一个object类型的数组为该回调方法提供参数.
private void buttonGetCustomer_Click(object sender, System.EventArgs e)
{
UpdateUI("开始检索客户名单...", null);
//下面我将讲述异步调用的三种方式,注意!!!!
//开始利用委托进行异步的方法调用,并在被调用方法异步执行完毕后自动调用MyCallback()
//瞧,我们还没办法以其他的方式挂上我们的回调方法,所以之前的两个委托类型声明的变量在这里就被用上了
GetCustomersHandler.BeginInvoke(CallbackHandler, null);
//我们也可以通过主线程中的一个while语句轮询BeginInvoke()返回的IAsyncResult.IsCompleted属性
//来查询异步调用的方法是否已经执行完毕
//也可以在主线程中使用BeginInvoke返回的IAsyncResult.AsyncWaitHandle属性来获取WaitHandle
//这个返回的WaitHandle允许客户端等待异步操作完成,而不是轮询IsCompleted。
//当异步调用完成时会发出WaitHandle信号
//我们可以通过调用WaitHandle.WaitOne()在EndInvoke()前等待它完成,当然这期间你可以干任何事情
//WaitHandle的WaitAny()、WaitAll()则用于作为参数的WaitHandle数组元素全部/任一收到完成信号
}
//关于Delegate.EndInvoke()方法的说明:
//EndInvoke()是阻塞方法,所以当异步调用的方法尚未执行完毕前它是不会返回的
//返回值就是调用BeginInvoke()的委托对应的方法返回值
//参数包括您需要异步执行的方法的 out 和 ref 参数以及由 BeginInvoke 返回的 IAsyncResult
private void MyCallback(IAsyncResult Iar)
{
try
{
string[] retList;
retList = GetCustomersHandler.EndInvoke(Iar);
UpdateUI("完成检索",retList);
}
catch (Exception e)
{
string Error;
Error = "错误:" + e.Message;
UpdateUI(Error, null);
}
}
//为了能以委托方式调用UpdateUI_Impl()方法,只得为其声明一个委托类型
public delegate void UpdateUIHandler(string statusMessage, string[] Customers);
private void UpdateUI(string statusMessage, string[] Customers)
{
//UpdateUI()的作用其实很简单,就是切换线程、给UpdateUI_Impl()传递参数而已
if (this.InvokeRequired) //还在辅助线程里呢
{
//瞧,这里不就用上了刚才说的那个委托类型吗?还得为其准备参数
UpdateUIHandler handler = new UpdateUIHandler(UpdateUI_Impl);
object[] args = new object[] {statusMessage, Customers};
//Control.BeginInvoke()的参数就不一样,是一个Delegate与该Delegate方法的参数表
//也是通过下面这个调用,UpdateUI()实现了线程的切换!
this.BeginInvoke(handler, args);
}
else //已经在主线程里了
{
UpdateUI_Impl(statusMessage, Customers);
}
}
private void UpdateUI_Impl(string statusMessage, string[] Customers)
{
//设置状态条的显示文本,将客户名单绑定为listBox的数据源进行显示
//如果前面使用了Panel,那么这里就该改为statusBar.Panels[0].Text = statusMessage;
statusBar.Text = statusMessage;
listBoxCustomer.DataSource = Customers;
}
private string[] GetCustomers()
{
//让这个被异步调用的方法休眠5000毫秒之后才返回值
Thread.Sleep(5000);
return new string[] {"张三","李四","王五","赵二","周六","钱七","孙八"};
}
}
}
posted on 2004-05-16 10:32 Abbey的网络日志 阅读(2278)