现在看到的方法有
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只能不阻塞后面代码的执行,不能解决画面假死