您的位置:首页 > 其它

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

2010-07-08 17:58 471 查看
由于 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}

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yjmyzz/archive/2007/12/20/1956101.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: