winform 跨线程访问问题
程序员文章站
2022-07-25 22:58:44
一、问题描述 进行winform 开发我们在进行数据交换时避免不了使用多线程或异步方法,这样操作也将避免不了跨线程对控件进行操作(赋值、修改属性)。 下面通过一个测试说明一下问题 点击一个按钮异步对textbox进行赋值 运行测试结果 1 private void button1_Click(obj ......
一、问题描述
进行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 }
产生错误的原因:textbox1是由主线程创建的,异步方法(或子线程)是另外创建的一个线程,在.net上执行的是托管代码,c#强制要求这些代码必须是线程安全的,即不允许跨线程访问windows窗体的控件。
二、解决方法
1.在窗体的加载事件中,将c#内置控件(control)类的checkforillegalcrossthreadcalls属性设置为false,屏蔽掉c#编译器对跨线程调用的检查。
1 //取消跨线程的访问 2 control.checkforillegalcrossthreadcalls = false;
使用上述的方法虽然可以保证程序正常运行并实现应用的功能,但是在实际的软件开发中,做如此设置是不安全的(不符合.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 }
我个人比较使用喜欢使用事件解决(原理同委托一样),但省掉不少代码
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 }