WinForm 子线程修改主线程(UI线程)

摘要:
无论是同步还是异步,逐步跟踪调试代码都会发现这些方法仍然会返回到UI线程执行,而UI线程只通过代理。这两个方法将消息放入UI线程的消息队列中。当UI线程处理消息时,它将在自己的上下文中执行传入方法。换句话说,所有使用BeginInvoke和Invoke的线程都在主UI线程中执行。因此,如果这些方法涉及一些静态变量,则不考虑锁定问题

原文http://www.cnblogs.com/SkySoot/archive/2012/03/14/2396552.html

我们先来看一段运行时会抛出 InvalidOperationException 异常的代码段:

 1 public partial class TestThread : Form
 2 {
 3     public TestThread()
 4     {
 5         InitializeComponent();
 6     }
 7  
 8     Thread thread;
 9  
10     void SetText(string str)
11     {
12         this.textBox1.Text = str;
13     }
14  
15     void DoSomething()
16     {
17         // do......
18         SetText("XXX");
19     }
20  
21     private void buttonX1_Click(object sender, EventArgs e)
22     {
23         thread = new Thread(new ThreadStart(DoSomething));
24         thread.IsBackground = true;
25         thread.Start();
26     }
27 }

image

在VS2005或者更高版本中,只要不是在控件的创建线程(一般就是指UI主线程)上访问控件的属性就会抛出这个错误,解决方法就是利用控件提供的Invoke和BeginInvoke把调用封送回UI线程,也就是让控件属性修改在UI线程上执行.

下面给出修改后正确调用的代码:

比较直接的修改方法像这样:

 1 public partial class TestThread : Form
 2 {
 3     delegate void ChangeTextBoxValue(string str); // 新增委托代理
 4  
 5     public TestThread()
 6     {
 7         InitializeComponent();
 8     }
 9  
10     Thread thread;
11  
12     void SetText(string str)
13     {
14         this.textBox1.Text = str;
15     }
16  
17     void DoSomething()
18     {
19         // do......
20         this.BeginInvoke(new ChangeTextBoxValue(SetText),"XXX"); // 也可用 this.Invoke调用
21     }
22  
23     private void buttonX1_Click(object sender, EventArgs e)
24     {
25         thread = new Thread(new ThreadStart(DoSomething));
26         thread.IsBackground = true;
27         thread.Start();
28     }
29 }

不过,要考虑到也许程序中不止子线程会调用 DoSomething()方法,也许主线程或其他模块多处调用这个方法,最漂亮的改法是这样:

 1 public partial class TestThread : Form
 2 {
 3     delegate void ChangeTextBoxValue(string str);
 4  
 5     public TestThread()
 6     {
 7         InitializeComponent();
 8     }
 9  
10     Thread thread;
11  
12     void SetText(string str)
13     {
14         if (this.InvokeRequired) // 获取一个值指示此次调用是否来自非UI线程
15         {
16             this.Invoke(new ChangeTextBoxValue(SetText), str);
17         }
18         else
19         {
20             this.textBox1.Text = str;
21         }            
22     }
23  
24     void DoSomething()
25     {
26         // do......
27         SetText("ABCDEFG");
28     }
29  
30     private void buttonX1_Click(object sender, EventArgs e)
31     {
32         thread = new Thread(new ThreadStart(DoSomething));
33         thread.IsBackground = true;
34         thread.Start();
35     }
36 }

this.Invoke(new ChangeTextBoxValue(SetText), str) // 在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托

this.BeginInvoke(new ChangeTextBoxValue(SetText), str); // 在创建控件的基础句柄所在线程上,用指定的参数异步执行指定委托。

无论是同步还是异步,单步跟踪调试代码会发现,这些方法还是会回到UI线程执行,其中通过了代理而已.

这两个方法向UI线程的消息队列中放入一个消息,当UI线程处理这个消息时,就会在自己的上下文中执行传入的方法,换句话说凡是使用BeginInvoke和Invoke调用的线程都是在UI主线程中执行的,所以如果这些方法里涉及一些静态变量,不用考虑加锁的问题.

免责声明:文章转载自《WinForm 子线程修改主线程(UI线程)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇牛客网2017校招真题在线编程之合唱团问题——动态规划问题首秀在 github 上获取源码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JAVA并发理解之重排序问题

 首先我们先来了解一下什么是重排序:重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。 从Java源代码到最终实际执行的指令序列,会分别经历下面3种重排序,如下图所示       上述的1属于编译器重排序,2和3属于处理器重排序。这些重排序可能会导致多线程程序出现内存可见性问题。在单线程程序中,对存在控制依赖的操作重排序,不会改变...

Winform中自定义xml配置文件,并配置获取文件路径

场景 在Winform程序中,需要将一些配置项存到配置文件中,这时就需要自定义xml的配置文件格式。并在一些工具类中去获取配置文件的路径并加载其内容。 关注公众号霸道的程序猿获取编程相关电子书、教程推送与免费下载。 实现 首先在项目下新建文件夹,命名为config,然后右键添加xml文件。 自定义xml节点内容如下 <?xml version="1...

WinForm窗体程序中使用CefSharp获取加载后的资源、截取request参数、拦截response数据、注入jquery文件和js代码(4)-注入jquery文件和js代码

源码地址:源代码csdn  或者底部qq问我要 六、注入jquery文件和js代码 在界面button按钮点击事件中 private void button1_Click(object sender, EventArgs e) { //注入本机binx86debug下的文件 browser.E...

Winform开发常用控件之TreeView菜单导航和权限用法

TreeView一个很棒的控件,我们在做WEB开发时常常犯困的一个东东。当然这里介绍winform里面的用法唠。 先介绍几个属性吧,CheckBoxes设置为true的话树形节点前面会出现checkbox勾选框、ImageList绑定树形里面的图标(界面上放一个Imgelist控件,绑定上即可)、ShowLines(树形展开时显示线条)等等 哦,这个方法好...

排查CPU占用过高的问题

背景 最近测试服出现了CPU异常高的情况,占用率接近 100%,所以写篇文章简单地记录下碰到这种情况,该如何去定位导致CPU异常的代码,下文介绍了几种比较常用的工具。 下文均基于测试代码。 准备 我们先准备一个测试项目,此处使用的是一个简单的 springboot 的 web 项目,直接跑去官网初始化一个,地址: 地址,然后写了段简单的示例代码,见下图。...

C# winform 获取标题栏,状态栏,菜单栏的高度

MessageBox.Show("当前窗体标题栏高度"+(this.Height - this.ClientRectangle.Height).ToString());//获得当前窗体标题栏高度 ClientRectangle//获取表示控件的工作区的矩形 MessageBox.Show(SystemInformation.PrimaryMo...