如何在多线程中调用winform窗体控件

由于 Windows 窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入 一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用和死锁的情况。于是在调试器中运行应用程序时,如果创建某控件的线程之外的其他线程试图 调用该控件,则调试器会引发一个 InvalidOperationException  

本文用一个很简单的示例来讲解这个问题(在窗体上放一个TextBox和一个Button,点击Button后,在新建的线程中设置TextBox的值)

解决办法一: 关闭该异常检测的方式来避免异常的出现

经过测试发现此种方法虽然避免了异常的抛出,但是并不能保证程序运行结果的正确性 (比如多个线程同时设置TextBox1的Text时,很难预计最终TextBox1的Text是什么)
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8using System.Threading;
9
10namespace winformTest
11{
12     public partial class Form1 : Form
13     {
14         public Form1()
15         {
16             InitializeComponent();
17             Control.CheckForIllegalCrossThreadCalls = false;//这一行是关键      
18         }
19        
20
21         private void button1_Click(object sender, EventArgs e)
22         {
23             SetTextBoxValue();
24         }
25
26         void SetTextBoxValue()
27         {
28             TextBoxSetValue tbsv = new TextBoxSetValue(this.textBox1, "Method1");
29             ThreadStart TS = new ThreadStart(tbsv.SetText);
30             Thread T = new Thread(TS);
31             T.Start();
32         }
33
34
35         class TextBoxSetValue
36         {
37             private TextBox _TextBox ;
38             private string _Value;
39
40             public TextBoxSetValue(TextBox TxtBox, String Value)
41             {
42                 _TextBox = TxtBox;
43                 _Value = Value;
44             }
45
46             public void SetText()
47             {
48                 _TextBox.Text = _Value;
49             }
50         }
51     }
52}
解决办法二:通过委托安全调用
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8
9namespace winformTest
10{
11     public partial class Form2 : Form
12     {
13         public Form2()
14         {
15             InitializeComponent();
16         }
17
18
19         private void button1_Click(object sender, EventArgs e)
20         {
21             SetTextBoxValue();
22         }        
23
24       
25         private delegate void CallSetTextValue();
26         //通过委托调用
27         void SetTextBoxValue()
28         {
29             TextBoxSetValue tbsv = new TextBoxSetValue(this.textBox1, "Method2");
30             if (tbsv.TextBox.InvokeRequired)
31             {
32                 CallSetTextValue call = new CallSetTextValue(tbsv.SetText);
33                 tbsv.TextBox.Invoke(call);               
34             }
35             else
36             {
37                 tbsv.SetText();
38             }
39         }
40
41
42         class TextBoxSetValue
43         {
44             private TextBox _TextBox;
45             private string _Value;
46
47             public TextBoxSetValue(TextBox TxtBox, String Value)
48             {
49                 _TextBox = TxtBox;
50                 _Value = Value;
51             }
52
53             public void SetText()
54             {
55                 _TextBox.Text = _Value;
56             }
57
58
59             public TextBox TextBox {
60                 set { _TextBox = value; }
61                 get { return _TextBox; }
62             }           
63         }
64     }
65}

第三解决办法:利用BackgroundWorker控件
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.Data;
5using System.Drawing;
6using System.Text;
7using System.Windows.Forms;
8using System.Threading;
9
10namespace winformTest
11{
12     public partial class Form3 : Form
13     {
14         public Form3()
15         {
16             InitializeComponent();
17         }
18
19         private void button1_Click(object sender, EventArgs e)
20         {
21             using (BackgroundWorker bw = new BackgroundWorker())
22             {
23                 bw.RunWorkerCompleted += SetTextBoxValue;
24                 bw.RunWorkerAsync();
25             }
26         }
27        
28         void SetTextBoxValue(object sender, RunWorkerCompletedEventArgs e)
29         {
30             TextBoxSetValue tbsv = new TextBoxSetValue(this.textBox1, "Method3");
31             tbsv.SetText();
32         }
33
34
35         class TextBoxSetValue
36         {
37             private TextBox _TextBox;
38             private string _Value;
39
40             public TextBoxSetValue(TextBox TxtBox, String Value)
41             {
42                 _TextBox = TxtBox;
43                 _Value = Value;
44             }
45
46             public void SetText()
47             {
48                 _TextBox.Text = _Value;
49             }
50         }
51
52     }
53} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值