您的位置:首页 > 其它

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

2008-11-19 10:49 411 查看

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



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

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

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

经过测试发现此种方法虽然避免了异常的抛出,但是并不能保证程序运行结果的正确性 (比如多个线程同时设置TextBox1的Text时,很难预计最终TextBox1的Text是什么)

1

using System;
2

using System.Collections.Generic;
3

using System.ComponentModel;
4

using System.Data;
5

using System.Drawing;
6

using System.Text;
7

using System.Windows.Forms;
8

using System.Threading;
9


10

namespace 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

}
解决办法二:通过委托安全调用

1

using System;
2

using System.Collections.Generic;
3

using System.ComponentModel;
4

using System.Data;
5

using System.Drawing;
6

using System.Text;
7

using System.Windows.Forms;
8


9

namespace 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控件

1

using System;
2

using System.Collections.Generic;
3

using System.ComponentModel;
4

using System.Data;
5

using System.Drawing;
6

using System.Text;
7

using System.Windows.Forms;
8

using System.Threading;
9


10

namespace 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

}
posted @ 2007-12-20 16:50 菩提树下的杨过 阅读(280) 评论(0) 编辑 收藏 网摘
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: