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

简介: 由于 Windows 窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用和死锁的情况。

由于 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}
目录
相关文章
System.InvalidOperationException:“线程间操作无效: 从不是创建控件“xxx”线程它。”
System.InvalidOperationException:“线程间操作无效: 从不是创建控件“xxx”线程它。”
473 0
|
4月前
|
C#
[C#] 如何在子线程中显示编辑控件内容
[C#] 如何在子线程中显示编辑控件内容
41 0
Auto.js 特殊定位控件方法 不能在ui线程执行阻塞操作,请使用setTimeout代替
Auto.js 特殊定位控件方法 不能在ui线程执行阻塞操作,请使用setTimeout代替
1289 0
Auto.js 特殊定位控件方法  不能在ui线程执行阻塞操作,请使用setTimeout代替
|
消息中间件 安全 C#
WinForm-跨线程更新UI控件常用方法
WinForm-跨线程更新UI控件常用方法
674 0
WinForm-跨线程更新UI控件常用方法
|
C#
WPF中窗口控件的跨线程调用
原文:WPF中窗口控件的跨线程调用 在WinForm中,我们要跨线程访问窗口控件,只需要设置属性CheckForIllegalCrossThreadCalls = false;即可。 在WPF中要麻烦一下,同样的不允许跨线程访问,因为没有权限,访问了会抛异常; 没有CheckForIllegalCrossThreadCalls 属性,怎么办? 在WPF中的窗口控件都有一个Dispatcher属性,允许访问控件的线程;既然不允许直接访问,就告诉控件我们要干什么就好了。
1972 0
C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
原文:C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较 使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新   使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和不夸跨线程执行UI更新报错的最佳实践,附加几种其他方式比较 由于是Winform代码和其他原因,本文章只做代码截图演示,不做界面UI展示,当然所有代码都会在截图展示。
4859 0
|
并行计算 API Windows
浅谈.NET下的多线程和并行计算(八)Winform中多线程编程基础上
首先我们创建一个Winform的应用程序,在上面添加一个多行文本框和一个按钮控件,按钮的事件如下: Thread.Sleep(1000); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) sb.Append("test"); string s = sb.ToString(); textBox1.Text = s; 首先我们可以把这个操作理解为一个非常耗时的操作,它至少占用1秒的时间。
784 0
|
并行计算
浅谈.NET下的多线程和并行计算(九)Winform中多线程编程基础下
在之前的文章中我们介绍过两种Timer和BackgroundWorker组件,在上文中我们提到过,强烈建议在UI线程上操作控件,否则很容易产生人品问题。可以想到,上次介绍的两个Timer基于ThreadPool,回调方法运行于不同于UI线程的新线程上,在这个方法中操作控件需要进行Invoke或BeginInvoke。
912 0
|
12天前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
38 1
|
4天前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。