Windows 窗体多线程 当我们在编写一个需要长时间运行的程序时(如数学计算,执行数据库命令,访问WebService)常常将它们写在一个组件中,让他们在后台运行.从而不影响Windows界面的显示和界面上的交互操作.但我们有时还是感到不怎方便,如我们不能直接应用winForm里定义的变量等.那么在UI进程中能否直接执行长时间运行的程序,而不影响UI进程呢 ? 下面的示例将解决这个问题. 本例利用多线程从长时间运行的操作(计算fbnc数列(n > 36 ))中分离出用户界面 (UI),以将用户的后续输入传递给辅助线程(CalHandler,showDel)以调节其行为与用户界面元素进行交互,从而实现稳定而正确的多线程处理的消息传递方案。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; namespace AsynchCalcPi { public partial class Form2 : Form { public Form2() { InitializeComponent(); Form2.calComplete += new CalHandler(Form2_calComplete); } void Form2_calComplete(string strTemp) { //为了对调用者屏蔽与此 UI 线程有关的线程安全通信信息, //ShowCalcResult 方法在此 UI 线程上通过 Control.BeginInvoke 方法使用 showDel 给自己发送消息。 //Control.BeginInvoke 异步队列为 UI 线程提供服务,并且不等待结果就继续运行。 if(!bClose ) this.BeginInvoke(new showDel(showRes ),strTemp ); } int times = 1; private void showRes(string strTemp) { times += 1; this.richTextBox1.AppendText("," + strTemp); this.progressBar1.Value = iStep * times%100; if (FinishFlag) { //timer1.Enabled = false; MessageBox.Show(strTemp); } } private delegate void showDel(string stemp); private void button1_Click(object sender, EventArgs e) { try { j = Int32.Parse(this.textBox_Num.Text.Trim()); iStep = 100 / j; if (j < 1) return; } catch { MessageBox.Show("请在文本框内输入数字字符"); return; } for (int i = 0; i < j; i++) this.richTextBox1.AppendText(this.ComputeFibonacci(i).ToString() + ","); } private long ComputeFibonacci(int n) { //' The parameter n must be >= 0 and <= 91. //' Fib(n), with n > 91, overflows a long. if (n < 0 || n > 91) { MessageBox.Show("value must be >= 0 and <= 91", "n"); } long result = 0; if (n < 2) result = 1; else { result = ComputeFibonacci(n - 1) + ComputeFibonacci(n - 2); } return result; } public int AddInterlink(int i) { if (i <= 0) return 0; else if (i > 0 && i <= 2) return 1; else return AddInterlink(i - 1) + AddInterlink(i - 2); } private void button2_Click(object sender, EventArgs e) { try { j = Int32.Parse(this.textBox_Num.Text.Trim()); iStep = 100 / j; if (j < 1) return; } catch { MessageBox.Show("请在文本框内输入数字字符"); return; } for (int i = 0; i < j; i++) this.richTextBox1.AppendText(this.AddInterlink(i).ToString() + ","); } private void button3_Click(object sender, EventArgs e) { try { j = Int32.Parse(this.textBox_Num.Text.Trim()); iStep = 100 / j; if (j < 1) return; } catch { MessageBox.Show("请在文本框内输入数字字符"); return; } ComputeFibonacciDel calcFbnc = new ComputeFibonacciDel(this.ComputeFibonacci); calcFbnc.BeginInvoke(j, callBack, null); } //实时显示通知服务 private long ShowCalcResult(int n) { long result1 = 0; for (int i = 0; i < n; i++) { result1 = this.ComputeFibonacci(i); //委托calComplete 由辅助线程用于向 UI 线程回传消息,通常是有关长时间运行的操作的最新进度。 calComplete(result1.ToString() ); } return result1; } //定义计算过程中用于传递消息的委托 public delegate void CalHandler(string strTemp); //定义事件 public static event CalHandler calComplete; //定义委托 进行异步计算Fibonacci数列 private delegate long ComputeFibonacciDel(int n); //定义引用在异步操作完成时调用的回调方法.用以在计算完成后取得返回值和当前状态. AsyncCallback callBack = new AsyncCallback(ShowResult); private static bool FinishFlag = false; static void ShowResult(IAsyncResult ar) { // Asynchronous Callback method. // Obtains the last parameter of the delegate call. int value = Convert.ToInt32(ar.AsyncState); // Obtains return value from the delegate call using EndInvoke. AsyncResult aResult = (AsyncResult)ar; ComputeFibonacciDel temp = (ComputeFibonacciDel)aResult.AsyncDelegate; long result = temp.EndInvoke(ar); FinishFlag = true; calComplete("当前状态代号:" + value.ToString() + " " + "计算后的返回结果:" + result.ToString()); } int i = 0; private void timer1_Tick(object sender, EventArgs e) { i += 1; i = i % 100; this.progressBar1.Value = i; } int j = 0; int iStep = 1; ComputeFibonacciDel calcFbnc; private void button4_Click(object sender, EventArgs e) { FinishFlag = false; //停止进度条的自动滚动.让进度条根据当前进度显示 this.timer1.Enabled = false; this.progressBar1.Value = 0; try { j= Int32.Parse(this.textBox_Num.Text.Trim()); iStep = 100 / j ; if (j < 1) return; } catch { MessageBox.Show("请在文本框内输入数字字符"); return; } //ComputeFibonacciDel,用于捆绑要传递给(从线程池中分配的)辅助线程上的ShowCalcResult 的参数。 //当用户决定要计算 fbnc数列 时,事件处理程序将创建此委托的一个实例。 //此工作通过调用 BeginInvoke 在线程池中进行排队。该委托实际上是由 UI 线程用于向辅助线程传递消息。 calcFbnc = new ComputeFibonacciDel(this.ShowCalcResult ); IAsyncResult aResult= calcFbnc.BeginInvoke(j,callBack , null); //已在callBack方法中写出,此处不再写此方法. /**/////Wait for the call to complete //aResult.AsyncWaitHandle.WaitOne(); //long callResult = calcFbnc.EndInvoke(aResult); } bool bClose = false; private void Form2_FormClosing(object sender, FormClosingEventArgs e) { bClose = true; } //参考资料: //http://www.microsoft.com/china/MSDN/library/archives/library/dnforms/html/winforms08162002.asp }} 源码: AsynchCalcFbnc