欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

winform 跨线程访问问题

程序员文章站 2022-04-24 10:13:04
一、问题描述 进行winform 开发我们在进行数据交换时避免不了使用多线程或异步方法,这样操作也将避免不了跨线程对控件进行操作(赋值、修改属性)。 下面通过一个测试说明一下问题 点击一个按钮异步对textbox进行赋值 运行测试结果 1 private void button1_Click(obj ......

一、问题描述

进行winform 开发我们在进行数据交换时避免不了使用多线程或异步方法,这样操作也将避免不了跨线程对控件进行操作(赋值、修改属性)。

下面通过一个测试说明一下问题

winform  跨线程访问问题

点击一个按钮异步对textbox进行赋值

运行测试结果

winform  跨线程访问问题

winform  跨线程访问问题
1 private void button1_click(object sender, eventargs e)
2 {        
3               action<string> action = new action<string>((str) =>
4               {
5                   // 解决跨线程赋值
6                   this.textbox1.text = str;              
7               });
8               action.begininvoke("test", null, null);      
9 }
view code

产生错误的原因:textbox1是由主线程创建的,异步方法(或子线程)是另外创建的一个线程,在.net上执行的是托管代码,c#强制要求这些代码必须是线程安全的,即不允许跨线程访问windows窗体的控件。

二、解决方法

1.在窗体的加载事件中,将c#内置控件(control)类的checkforillegalcrossthreadcalls属性设置为false,屏蔽掉c#编译器对跨线程调用的检查。

winform  跨线程访问问题
1 //取消跨线程的访问
2 control.checkforillegalcrossthreadcalls = false;
view code

使用上述的方法虽然可以保证程序正常运行并实现应用的功能,但是在实际的软件开发中,做如此设置是不安全的(不符合.net的安全规范),在产品软件的开发中,此类情况是不允许的。如果要在遵守.net安全标准的前提下,实现从一个线程成功地访问另一个线程创建的空间,要使用c#的方法回调机制。

2.使用回调函数 ( 委托的应用 )

(1) 定义声明回调

(2) 初始化回调

(3) 触发动作

winform  跨线程访问问题
 1         /// <summary>
 2         /// 定义委托
 3         /// </summary>
 4         /// <param name="str"></param>
 5         private delegate void setvaluedelegate(string str);
 6 
 7         /// <summary>
 8         /// 声明委托
 9         /// </summary>
10         setvaluedelegate test;
11 
12         /// <summary>
13         /// 回调方法
14         /// </summary>
15         /// <param name="str"></param>
16         private void settbvalue(string str)
17         {
18             this.textbox1.text = str;
19         }
20 
21         private void button1_click(object sender, eventargs e)
22         {
23             // 实例化委托    
24             test = new setvaluedelegate(settbvalue);
25 
26             action<string> action = new action<string>((str) =>
27             {
28                   // 解决跨线程赋值                 
29                   this.textbox1.invoke(test, str);
30              });
31 
32             action.begininvoke("test", null, null);
33         }
view code

我个人比较使用喜欢使用事件解决(原理同委托一样),但省掉不少代码

winform  跨线程访问问题
 1         private void button1_click(object sender, eventargs e)
 2         {
 3             action<string> action = new action<string>((str) =>
 4               {
 5                   // 解决跨线程赋值            
 6                   this.textbox1.invoke(
 7                       new action<string>((param) =>
 8                       {
 9                           this.textbox1.text = param;
10                       }
11                       ), str);
12               });
13 
14             action.begininvoke("test", null, null);
15         }
view code