winform 跨线程访问问题

一、问题描述

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

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

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

运行测试结果

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#编译器对跨线程调用的检查。

1 //取消跨线程的访问
2 Control.CheckForIllegalCrossThreadCalls = false;
View Code

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

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

(1) 定义声明回调

(2) 初始化回调

(3) 触发动作

 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

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

 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

 

posted @ 2019-02-22 15:16  小小糖  阅读(1281)  评论(0编辑  收藏  举报