现在看到的方法有
1.掩耳盗铃法(Control.CheckForIllegalCrossThreadCalls?=?false;)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
using ?System;
using ?System.Threading;
using ?System.Windows.Forms;
?
namespace ?ThreadTest
{ ???? public ?partial? class ?Form1?:?Form
???? {????????
?
???????? public ?Form1()
???????? {
???????????? InitializeComponent();
???????????? Control.CheckForIllegalCrossThreadCalls?=? false ; //这一行是关键??????
???????? }
??????? ??
???????? private ?void ?btnSet_Click( object ?sender,?EventArgs?e)
???????? {???????????
???????????? Thread?t?=? new ?Thread( new ?ParameterizedThreadStart(SetTextBoxValue));
???????????? t.Start( "Hello?World" );
???????? }
?
?
???????? void ?SetTextBoxValue( object ?obj)?
???????? {
???????????? this .textBox1.Text?=?obj.ToString();
???????? }????????
???? }
} |
这种方法是最方便,实现最简单的方式,但是这样等于是线程之间是去了限制,子线程能够直接控制父线程的控件,会出现线程之间的冲突,不是好的实现方式
2.利用BackgroundWorker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
using ?System;
using ?System.ComponentModel;
using ?System.Windows.Forms;
?
namespace ?ThreadTest
{ ???? public ?partial? class ?Form1?:?Form
???? {
???????? public ?Form1()
???????? {
???????????? InitializeComponent();????????????
???????? }???????
?
???????? private ?void ?btnSet_Click( object ?sender,?EventArgs?e)
???????? {
???????????? //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
???????????? using ?(BackgroundWorker?bw?=? new ?BackgroundWorker())
???????????? {
???????????????? bw.RunWorkerCompleted?+=? new ?RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
???????????????? bw.DoWork?+=? new ?DoWorkEventHandler(bw_DoWork);
???????????????? bw.RunWorkerAsync( "Hello?World" );
???????????? }
???????? }
?
???????? void ?bw_DoWork( object ?sender,?DoWorkEventArgs?e)
???????? {
???????????? //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
???????????? e.Result?=?e.Argument; //这里只是简单的把参数当做结果返回,当然您也可以在这里做复杂的处理后,再返回自己想要的结果(这里的操作是在另一个线程上完成的)
???????? }
?
???????? void ?bw_RunWorkerCompleted( object ?sender,?RunWorkerCompletedEventArgs?e)
???????? {
???????????? //这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了
???????????? this .textBox1.Text?=?e.Result.ToString();
???????????? //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
???????? }???????
???? }????
} |
这种方式只能在异步结束后给控件赋值,
--即bw_DoWork是异步处理,异步处理过程中不能给控件赋值
--bw_RunWorkerCompleted方法中可以给控件赋值,可是这个过程不是异步的,如果在bw_RunWorkerCompleted中加上一个System.Threading.Thread.Sleep(3000);画面还是会假死
3.不使用BackgroundWorker,自己来写线程来实现类似于BackgroundWorker的处理
子线程给主线程成员赋值的迷惑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
???????? //?代码中自己定义的按钮(非显示按钮)
???????? private ?Button?testBtn?=? new ?Button();
?
???????? private ?void ?button1_Click( object ?sender,?EventArgs?e)
???????? {
???????????? Thread?thr?=? new ?Thread(ControlParent);
???????????? thr.Start();
???????? }
?
???????? private ?void ?ControlParent()
???????? {
???????????? Thread.Sleep(3000);
???????????? //?给自己定义的按钮赋值没有问题
???????????? testBtn.Text?=? "eeee" ;
???????????? //?给画面上显示的按钮赋值,InvalidOperationException错误(这里迷糊了,子线程不能直接给主线程赋值,那么主线程是什么?)
???????????? this .button1.Text?=? "asda" ; //?InvalidOperationException!!!!!!!!!!!
???????? }
|
这里的两个按钮,同样是属于一个类,只不过一个显示在画面上,另一个只定义了没有显示,为什么一个赋值成功,另一个就是败了,求大哥大姐们来个破解之法,感激不尽。
PS:窗体的this.BeginInvoke只能不阻塞后面代码的执行,不能解决画面假死