博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#跨线程操作控件的最简单实现探究
阅读量:5285 次
发布时间:2019-06-14

本文共 3994 字,大约阅读时间需要 13 分钟。

随着程序复杂度的提高,程序不可避免会出现多个线程,此时就很可能存在跨线程操作控件的问题。

 

跨线程操作UI控件主要有三类方式:

1、禁止系统的线程间操作检查。(此法不建议使用

2、使用Invoke(同步)或者BeginInvoke(异步)。(使用委托实现,并用lambda表达式简化代码

3、使用BackgroundWorker组件。(此法暂不介绍,详情可见文末的参考资料

 

先看一个跨线程操作失败的例子:

新建一个Winform窗口程序项目,拖一个button1和label1控件到Form1窗体上。启动程序以后试图通过点击button1改变label1的值,完整代码如下:

1 using System; 2 using System.Threading; 3 using System.Windows.Forms; 4  5 namespace Windows跨线程调用控件 6 { 7     public partial class Form1 : Form 8     { 9         public Form1()10         {11             InitializeComponent();12         }13 14         private void button1_Click(object sender, EventArgs e)15         {16             Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));17             thread1.Start("label已更新");18         }19         20         private void UpdateLabel(object str)21         {22             label1.Text = str.ToString();23         }24     }25 }

点击button1以后运行报错:

 

解决方案:

方法一:禁止系统的线程间操作检查。

代码就一句话:Control.CheckForIllegalCrossThreadCalls = false;通常写在Form1类的构造方法Form1()中。如下所示:

1 public Form1()2         {3             InitializeComponent();4 5             Control.CheckForIllegalCrossThreadCalls = false;         6         }

但是,这种方法是很不可靠的,有时候还是会报错。

 

方法二:使用Invoke(同步)或者BeginInvoke(异步)最精简的代码如下:

1 using System; 2 using System.Threading; 3 using System.Windows.Forms; 4  5 namespace Windows跨线程调用控件 6 { 7     public partial class Form1 : Form 8     { 9         public Form1()10         {11             InitializeComponent();12         }13 14         private void button1_Click(object sender, EventArgs e)15         {16             Thread thread1 = new Thread(UpdateLabel);//可以省略线程的委托类型ParameterizedThreadStart17             thread1.Start("label已更新");18         }19 20         private void UpdateLabel(object str)21         {22             if (label1.InvokeRequired)//不同线程为true,所以这里是true23             {               24                 BeginInvoke(new Action
(x => {label1.Text = x.ToString();}),str); 25 }26 }27 }28 }

说明:Action是.NET预定义好的委托,可以简化委托的语法,如果不清楚它的用法,可以搜索“Action和Func的用法”。

 

将上面的两种方法总结在同一段程序里面如下所示:(注意看代码中的注释)

1 using System; 2 using System.Threading; 3 using System.Windows.Forms; 4  5 namespace Windows跨线程调用控件 6 { 7     public partial class Form1 : Form 8     { 9         public Form1()10         {11             InitializeComponent();12 13             /************* 方法一 ************/14             //Control.CheckForIllegalCrossThreadCalls = false;15 16         }17 18         private void button1_Click(object sender, EventArgs e)19         {20             Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));21             thread1.Start("label已更新");22         }23 24 25         //如果控件的 Handle(句柄) 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。26         private void UpdateLabel(object str)27         {28             if (label1.InvokeRequired)//当是不同的线程在访问时为true,所以这里是true29             {30                 /************* 方法二 ************/31                 //Action
actionDelegate = (x) => { this.label1.Text = x.ToString(); };32 33 ////如果已经创建控件的句柄,则除了 InvokeRequired 属性以外,控件上还有四个可以从【任何线程】上安全调用的方法,34 ////它们是:Invoke、BeginInvoke、EndInvoke 和 CreateGraphics。 35 ////在后台线程上创建控件的句柄之前调用 CreateGraphics 可能会导致非法的跨线程调用。 36 ////对于所有其他方法调用,则应使用调用 (invoke) 方法之一封送对控件的线程的调用。37 //this.label1.BeginInvoke(actionDelegate, str);38 39 40 /************* 方法二(变式) ************/41 //也可以直接用下面一句话来完成42 //Control.BeginInvoke 方法有两个重载:BeginInvoke(Delegate) ,BeginInvoke(Delegate, Object[]),下式用的是第二个重载43 this.BeginInvoke(new Action
((x) => { label1.Text = x.ToString(); }), str);44 45 //如果启动的多线程不需要带可变的参数,那更简单:46 //label1.BeginInvoke(new Action(() => { label1.Text = "aaa"; })); 47 }48 }49 }50 }

参考资料:

转载于:https://www.cnblogs.com/xh6300/p/6067615.html

你可能感兴趣的文章
MauiMETA工具的使用(一)
查看>>
LeetCode: Anagrams 解题报告
查看>>
Qt 中获取本机IP地址
查看>>
070102_赌博设计:概率的基本概念,古典概型
查看>>
IT人生的价值和意义 感觉真的有了
查看>>
JS DOM对象
查看>>
OGR – Merging Multiple SHP files
查看>>
创业公司该不该被收购?(转)
查看>>
sqlserver 行转列、列转行[转]
查看>>
【IScroll深入学习】解决IScroll疑难杂症
查看>>
python 数据类型
查看>>
108-PHP类成员protected和private成员属性不能被查看数值
查看>>
css控制height充满浏览器视口
查看>>
python学习之 - XML
查看>>
Python--GIL 详解
查看>>
大道至简读后感(第四章)
查看>>
IDA IDC Tutorials: Additional Auto-Commenting
查看>>
k8s-存储卷1-十二
查看>>
INSERT IGNORE INTO / REPLACE INTO
查看>>
Python数据类型-布尔/数字/字符串/列表/元组/字典/集合
查看>>