Windows 窗体多线程
当我们在编写一个需要长时间运行的程序时(如数学计算,执行数据库命令,访问WebService)
常常将它们写在一个组件中,让他们在后台运行.从而不影响Windows界面的显示和界面上的交
互操作.但我们有时还是感到不怎方便,如我们不能直接应用winForm里定义的变量等.那么在
UI进程中能否直接执行长时间运行的程序,而不影响UI进程呢?
下面的示例将解决这个问题.
本例利用多线程从长时间运行的操作(计算fbnc数列(n>36))中分离出用户界面 (UI),
以将用户的后续输入传递给辅助线程(CalHandler,showDel)以调节其行为与用户界面元素
进行交互,从而实现稳定而正确的多线程处理的消息传递方案。
当我们在编写一个需要长时间运行的程序时(如数学计算,执行数据库命令,访问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
}
}