C#.NET跨线程控件的相关操作
来源:百度文库 编辑:神马文学网 时间:2024/04/26 04:16:54
在.NET中,如果我们在非UI线程上访问窗体上的控件的时候,会产生一个跨线程调用的异常,那么如何处理这种情况呢?在上一章中,我介绍了使用Control.Invoke方法,如果你不习惯使用委托,那么.Net还为我们提供了一个组件BackgroundWorker,你可以使用这个组件,以事件的方式去处理这种跨线程的控件访问。下面我就来详细的介绍一下这个组件的用法。
我们先来看一下BackgroundWorker提供了哪些常用的成员,
事件
◆DoWork:我们在这个事件中,执行需要异步处理的工作。
◆ProgressChanged:我们在这个事件中,接收并处理异步处理过程中的信息。
◆RunWorkerCompleted:我们在这个事件中,执行异步处理结束的工作。
方法
◆RunWorkerAsync()和RunWorkerAsync(object argument):这两个方法触发DoWork事件,开始异步操作。
◆ReportProgress(int percentProgress)和ReportProgress(int percentProgress, object userState):这两个方法触发ProgressChanged事件。
◆CancelAsync:结束后台的异步操作。
属性
◆bool CancellationPending:指示当前的后台的异步操作是否正在被取消,执行CancelAsync方法会导致这个属性为true。
◆bool IsBusy:指示当前的后台异步操作是否正在进行,进行中为true。
◆bool WorkerReportsProgress:获取或设置当前的BackgroundWorker是否可以执行ProgressChanged方法。
◆bool WorkerSupportsCancellation:获取或设置当前的BackgroundWorker是否可以执行CancelAsync方法。
OK,有了上面这些成员,我们来看一下BackgroundWorker是如何工作的。
Step 1. 当然是定义一个BackgroundWorker的实例,你可以从工具箱中拖拽一个BackgroundWorker控件到窗体上或者在代码中直接声明;
Step 2. 生成DoWork事件并在DoWork事件的中添加需要异步执行的代码。在异步执行的代码中,如果需要处理界面中的控件,请调用ReportProgress方法,而不要直接处理(例如给控件赋值),因为DoWork事件跟正常的界面的事件不同,这个事件在非UI线程上执行,所以才能异步执行。
Step 3. 生成ProgressChanged事件并添加控件处理的代码,因为这个事件是在UI线程上执行的,所以可以给界面中的控件进行赋值等操作。
Step 4. 如果需要,请生成RunWorkerCompleted事件,在此处理异步执行结束的业务逻辑。当然,此事件也是在UI线程上执行的,可以给界面中的控件进行赋值等操作。
Step 5. 在需要执行异步操作的地方调用RunWorkerAsync方法,开始执行异步调用。
下面是具体的代码:
01 public Form1()
02 {
03 InitializeComponent();
04 bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
05 bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
06 bWorker.ProgressChanged += new ProgressChangedEventHandler(bWorker_ProgressChanged);
07 this.Text = "UI thread id is:" + Thread.CurrentThread.ManagedThreadId.ToString();
08 }
09 BackgroundWorker bWorker = new BackgroundWorker();
10 void bWorker_DoWork(object sender, DoWorkEventArgs e)
11 {
12 int tick = (int)e.Argument;
13 Thread thr = Thread.CurrentThread;
14 for (int i = 0; i < 30; i++)
15 {
16 if (bWorker.CancellationPending)
17 {
18 e.Cancel = true;
19 //break;
20 }
21 else
22 {
23 Thread.Sleep(TimeSpan.FromSeconds(tick));
24 bWorker.ReportProgress(i, DateTime.Now.ToString() + "\\TID:" + thr.ManagedThreadId.ToString());
25 }
26 }
27
28 }
29 void bWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
30 {
31 progressBar1.Value = e.ProgressPercentage;
32 label1.Text = e.UserState.ToString();
33 }
34 void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
35 {
36 label1.Text = DateTime.Now.ToString();
37 progressBar1.Value = progressBar1.Maximum;
38 if (e.Cancelled)
39 label1.Text = "User cancelled.";
40 }
41 private void btnInvoke_Click(object sender, EventArgs e)
42 {
43 bWorker.WorkerReportsProgress = true;
44 bWorker.WorkerSupportsCancellation = true;
45 if (!bWorker.IsBusy)
46 bWorker.RunWorkerAsync(1);
47 }
48 private void btnCancel_Click(object sender, EventArgs e)
49 {
50 if (bWorker.WorkerSupportsCancellation)
51 bWorker.CancelAsync();
52 }
上面的代码请注意几个地方:
1. 第45行,开始调用RunWorkerAsync方法前,请先判断IsBusy属性是否是false,因为如果为true,则说明上一次的调用还没有结束,再次调用会引发异常。
2. 第50行,调用CancelAsync方法前,请先设置WorkerSupportsCancellation属性为true,否则会引发异常。
3. 第43行,调用ReportProgress方法前,请先设置WorkerReportsProgress属性为true,否则会引发异常。
4. RunWorkerAsync方法传递的参数是object类型,这个参数的值可以在DoWork事件的参数e中的属性Argument获得。
5. ReportProgress方法传递的参数可以在事件ProgressChanged中的参数e中获得。
6. 调用CancelAsync方法只是向后台的异步线程发出结束申请,具体什么时候结束,由线程自动管理。
7. 在RunWorkerCompleted事件中,如果想知道后台任务是正常执行完毕还是被调用CancelAsync方法强制中断,请参考事件的参数e的Cancelled属性。(奇怪的是这个属性不会在你调用CancelAsync方法后自动设置为true,你需要象代码中的20行那样进行设置。)
8. 请注意第7行和第26行的代码,这两段代码中的线程的ID,说明了DoWork事件和UI是在两个不同的线程上执行。
实际上BackgroundWorker并非直接用来解决跨线程的控件调用的问题,只是它提供了一种工作机制,可以让你的程序利用它来执行异步调用,并且在异步调用的过程中进行控件的操作。
好了,关于如何对界面中的控件进行跨线程的调用就介绍这么多吧,希望对大家有所帮助。
引用自链接:http://www.cnblogs.com/ATree/archive/2010/08/03/BackgroundWorker-DoWork.html
原文标题: 在.Net中进行跨线程的控件操作
原文链接:http://www.cnblogs.com/happinessCodes/archive/2010/07/22/1783199.html
我们先来看一下BackgroundWorker提供了哪些常用的成员,
事件
◆DoWork:我们在这个事件中,执行需要异步处理的工作。
◆ProgressChanged:我们在这个事件中,接收并处理异步处理过程中的信息。
◆RunWorkerCompleted:我们在这个事件中,执行异步处理结束的工作。
方法
◆RunWorkerAsync()和RunWorkerAsync(object argument):这两个方法触发DoWork事件,开始异步操作。
◆ReportProgress(int percentProgress)和ReportProgress(int percentProgress, object userState):这两个方法触发ProgressChanged事件。
◆CancelAsync:结束后台的异步操作。
属性
◆bool CancellationPending:指示当前的后台的异步操作是否正在被取消,执行CancelAsync方法会导致这个属性为true。
◆bool IsBusy:指示当前的后台异步操作是否正在进行,进行中为true。
◆bool WorkerReportsProgress:获取或设置当前的BackgroundWorker是否可以执行ProgressChanged方法。
◆bool WorkerSupportsCancellation:获取或设置当前的BackgroundWorker是否可以执行CancelAsync方法。
OK,有了上面这些成员,我们来看一下BackgroundWorker是如何工作的。
Step 1. 当然是定义一个BackgroundWorker的实例,你可以从工具箱中拖拽一个BackgroundWorker控件到窗体上或者在代码中直接声明;
Step 2. 生成DoWork事件并在DoWork事件的中添加需要异步执行的代码。在异步执行的代码中,如果需要处理界面中的控件,请调用ReportProgress方法,而不要直接处理(例如给控件赋值),因为DoWork事件跟正常的界面的事件不同,这个事件在非UI线程上执行,所以才能异步执行。
Step 3. 生成ProgressChanged事件并添加控件处理的代码,因为这个事件是在UI线程上执行的,所以可以给界面中的控件进行赋值等操作。
Step 4. 如果需要,请生成RunWorkerCompleted事件,在此处理异步执行结束的业务逻辑。当然,此事件也是在UI线程上执行的,可以给界面中的控件进行赋值等操作。
Step 5. 在需要执行异步操作的地方调用RunWorkerAsync方法,开始执行异步调用。
下面是具体的代码:
01 public Form1()
02 {
03 InitializeComponent();
04 bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
05 bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bWorker_RunWorkerCompleted);
06 bWorker.ProgressChanged += new ProgressChangedEventHandler(bWorker_ProgressChanged);
07 this.Text = "UI thread id is:" + Thread.CurrentThread.ManagedThreadId.ToString();
08 }
09 BackgroundWorker bWorker = new BackgroundWorker();
10 void bWorker_DoWork(object sender, DoWorkEventArgs e)
11 {
12 int tick = (int)e.Argument;
13 Thread thr = Thread.CurrentThread;
14 for (int i = 0; i < 30; i++)
15 {
16 if (bWorker.CancellationPending)
17 {
18 e.Cancel = true;
19 //break;
20 }
21 else
22 {
23 Thread.Sleep(TimeSpan.FromSeconds(tick));
24 bWorker.ReportProgress(i, DateTime.Now.ToString() + "\\TID:" + thr.ManagedThreadId.ToString());
25 }
26 }
27
28 }
29 void bWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
30 {
31 progressBar1.Value = e.ProgressPercentage;
32 label1.Text = e.UserState.ToString();
33 }
34 void bWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
35 {
36 label1.Text = DateTime.Now.ToString();
37 progressBar1.Value = progressBar1.Maximum;
38 if (e.Cancelled)
39 label1.Text = "User cancelled.";
40 }
41 private void btnInvoke_Click(object sender, EventArgs e)
42 {
43 bWorker.WorkerReportsProgress = true;
44 bWorker.WorkerSupportsCancellation = true;
45 if (!bWorker.IsBusy)
46 bWorker.RunWorkerAsync(1);
47 }
48 private void btnCancel_Click(object sender, EventArgs e)
49 {
50 if (bWorker.WorkerSupportsCancellation)
51 bWorker.CancelAsync();
52 }
上面的代码请注意几个地方:
1. 第45行,开始调用RunWorkerAsync方法前,请先判断IsBusy属性是否是false,因为如果为true,则说明上一次的调用还没有结束,再次调用会引发异常。
2. 第50行,调用CancelAsync方法前,请先设置WorkerSupportsCancellation属性为true,否则会引发异常。
3. 第43行,调用ReportProgress方法前,请先设置WorkerReportsProgress属性为true,否则会引发异常。
4. RunWorkerAsync方法传递的参数是object类型,这个参数的值可以在DoWork事件的参数e中的属性Argument获得。
5. ReportProgress方法传递的参数可以在事件ProgressChanged中的参数e中获得。
6. 调用CancelAsync方法只是向后台的异步线程发出结束申请,具体什么时候结束,由线程自动管理。
7. 在RunWorkerCompleted事件中,如果想知道后台任务是正常执行完毕还是被调用CancelAsync方法强制中断,请参考事件的参数e的Cancelled属性。(奇怪的是这个属性不会在你调用CancelAsync方法后自动设置为true,你需要象代码中的20行那样进行设置。)
8. 请注意第7行和第26行的代码,这两段代码中的线程的ID,说明了DoWork事件和UI是在两个不同的线程上执行。
实际上BackgroundWorker并非直接用来解决跨线程的控件调用的问题,只是它提供了一种工作机制,可以让你的程序利用它来执行异步调用,并且在异步调用的过程中进行控件的操作。
好了,关于如何对界面中的控件进行跨线程的调用就介绍这么多吧,希望对大家有所帮助。
引用自链接:http://www.cnblogs.com/ATree/archive/2010/08/03/BackgroundWorker-DoWork.html
原文标题: 在.Net中进行跨线程的控件操作
原文链接:http://www.cnblogs.com/happinessCodes/archive/2010/07/22/1783199.html
C#.NET跨线程控件的相关操作
子线程中操作控件
windows 控件限制用户的基本法门(c#.net 篇)
C#/.net里客户端控件如何控制/引用服务器端控件
ASP.NET与JavaScript操作CheckBox控件
vb.net的ListBox控件
vb.net的Combobox控件
善用 .NET 的 PropertyGrid 控件
ASP.NET 3.5中的ListView控件和DataPager控件-其它相关问题-华夏...
Visual Basic 6.0 控件和 .NET 控件的区别(续)
ASP.NET 服务器控件的验证
vb.net的Combobox控件1
vb.net的Combobox控件_翼心网
C#中对AxSpreadsheet控件的操作
VB控件数组的操作技巧2
C 的文件操作
VB.NET菜单项目相关操作技巧分享
pthread_cond_signal()的具体位置? - C/C - ChinaUnix.net
Win32环境下两种用于C 的线程同步类
C 对象是怎么死的?Win32线程篇
C#.Net的面试试题
vb.net控件
Servlet线程安全相关问题
vb.net入门——DomainUpDown 控件的使用