使用BackGroundWorker在多线程中访问Winform控件,当不是创建这个控件的线程访问控件时,把线程调整到是创建这个控件的线程去控制。,代码为红色的
多线程访问控件在网上的方法有很多,这里只记录我用到的这个,其他的可以去网上搜索,很多。
首先声明一个全局变量和一个委托类型(用来访问控件)
01.private BackgroundWorker _bWorker;
02.delegate void SetProgressBarDelegate(int value);
在一个按钮事件里面给这个workfer赋值一些属性
01._bWorker = new BackgroundWorker();
02. _bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
03. _bWorker.WorkerReportsProgress = true;
04. _bWorker.WorkerSupportsCancellation = true;
05.
06. _bWorker.RunWorkerAsync();
07. _bWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs ex)
08. {
09. if (proBarState.InvokeRequired)
10. {
11. SetProgressBarDelegate setProgressBar = new SetProgressBarDelegate(delegate(int value)
12. {
13. proBarState.Value = ex.ProgressPercentage;
14. });
15. this.Invoke(setProgressBar);
16. }
17. else
18. {
19. proBarState.Value = ex.ProgressPercentage;
20. }
21. };
22. _bWorker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs ex)
23. {
24.
25.
26. if (ex.Cancelled)
27. {
28. lblState.Text = "dd";
29. proBarState.Value = 0;
30. }
31. else
32. {
33. lblState.Text = "ss";
34. }
35. };
01.void bWorker_DoWork(object sender, DoWorkEventArgs e) 02. { 03. 04. //function to do work 05. if (_bWorker.CancellationPending) 06. { 07. e.Cancel = true; 08. } 09. }
上面的代码最重要的部分是红字的那this.Invoke(setProgressBar);这句话的意思是winfrom应用程序的主线程(创建控件的那个线程)给控件赋值。this代表主线程。
InvokeRequired属性查找msdn:获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。也就是说如果控件位于创建控件的线程(主线程)之外,就需要使用invoke方法将操作控件的方法推送到合适的线程(主线程)中执行。
还有一个设置什么全局属性的(忘了,大意是不检测跨线程访问控件安全性的,那个是全局属性,一个地方设置了其他都是如此,在其他需要检测安全性的地方容易出bug),那个不可取。