💈 A Cross-Thread Call Helper Class
Conmajia © 2012, 2018
Published on August 5th, 2012
Updated on February 2nd, 2019
Introduction
While working on background threads, you may encounter updating values of frontend GUI controls. Then you probably will face one particular problem: invalid operation between threads. As shown in figure 1, this issue throws an InvalidOperationException
. It occurs every time when accesses properties/methods from other threads but the one which owns them.

In .NET Framework, version 2.0 as I refer, every Control
class contains an InvokeRequired
property and an Invoke
method to accomplish cross-thread operations. Some typical call code is listed below.
public void DoWork() {
if (control.InvokeRequired) {
control.Invoke(DoWork);
}
else {
// do work
}
}
My Approach
I wrote a helper class InvokeHelper
which granted me the power to access assets between different threads. The class has 3 methods:
Invoke()
- to call methods of a control.
InvokeHelper.Invoke(<control>, "<method>"[, <param1>[,<param2>,...]]);
Get()
- to get properties of a control.
InvokeHelper.Get(<control>, "<property>");
Set()
- to set properties of a control.
InvokeHelper.Set(<control>, "<property>", <value>);
Demonstration
In the demo, I used a forever looping background thread (t
) to show how the InvokeHelper
helps threads to interact. Thread t
updates the frontend thread (the GUI) every 500 milliseconds.
Thread t;
private void button1_Click(object sender, EventArgs e) {
if(t == null) {
t = new Thread(multithread);
t.Start();
label4.Text = string.Format("Thread state:\n{0}", t.ThreadState.ToString());
}
}
public void DoWork(string msg) {
this.label3.Text = string.Format("Invoke method: {0}", msg);
}
int count = 0;
void multithread() {
while(true) {
InvokeHelper.Set(this.label1, "Text", string.Format("Set value: {0}", count));
InvokeHelper.Set(this.label1, "Tag", count);
string value = InvokeHelper.Get(this.label1, "Tag")
.ToString();
InvokeHelper.Set(this.label2, "Text", string.Format("Get value: {0}", value));
InvokeHelper.Invoke(this, "DoWork", value);
Thread.Sleep(500);
count++;
}
}
Results shown in animated figure 2. Obviously, the frontend is not blocked despite t
never stops.

InvokeHelper
Demonstration (animation)Other Approaches
There is a built-in option in the VisualStudio IDE that disables the cross-thread access check: CheckForIllegalCrossThreadCalls
. I found it slightly slower than my helper class. Figure 3 shows the test result.

CheckForIllegalCrossThreadCalls
The whole procedure of the test is recorded in figure 4. (The video lasts for 8'51")

CheckForIllegalCrossThreadCalls
(8'51")Appendix
Source code of the InvokeHelper
is listed below. Zipped .NET project files: Download
public class InvokeHelper {
private delegate object MethodInvoker(Control control, string methodName, params object[] args);
private delegate object PropertyGetInvoker(Control control, object noncontrol, string propertyName);
private delegate void PropertySetInvoker(Control control, object noncontrol, string propertyName, object value);
private static PropertyInfo GetPropertyInfo(Control control, object noncontrol, string propertyName) {
if (control != null && !string.IsNullOrEmpty(propertyName)) {
PropertyInfo pi = null;
Type t = null;
if (noncontrol != null) t = noncontrol.GetType();
else t = control.GetType();
pi = t.GetProperty(propertyName);
if (pi == null) throw new InvalidOperationException(string.Format("Can't find property {0} in {1}.", propertyName, t.ToString()));
return pi;
} else throw new ArgumentNullException("Invalid argument.");
}
public static object Invoke(Control control, string methodName, params object[] args) {
if (control != null && !string.IsNullOrEmpty(methodName))
if (control.InvokeRequired) return control.Invoke(new MethodInvoker(Invoke), control, methodName, args);
else {
MethodInfo mi = null;
if (args != null && args.Length > 0) {
Type[] types = new Type[args.Length];
for (int i = 0; i
References
- Sergiu Josan, Making Controls Thread-safely, May 2009
- vicoB, Extension of safeInvoke, July 2010
The End. \(\Box\)
💈 A Cross-Thread Call Helper Class的更多相关文章
- update the UI property cross thread
this.Invoke((MethodInvoker)delegate { txtResult.Text = sbd.ToString(); // runs on UI thread });
- Flink - Checkpoint
Flink在流上最大的特点,就是引入全局snapshot, CheckpointCoordinator 做snapshot的核心组件为, CheckpointCoordinator /** * T ...
- [转]How to display the data read in DataReceived event handler of serialport
本文转自:https://stackoverflow.com/questions/11590945/how-to-display-the-data-read-in-datareceived-event ...
- c#子线程线程中操作窗体更新的报错
用 在执行上传时,由于操作较长窗体界面卡住,于是用task解决 Task t1 = new Task(manage.UploadData); t1.Start(); 结果不卡了,程序也传完了,运行到更 ...
- 进程创建过程详解 CreateProcess
转载请您注明出处:http://www.cnblogs.com/lsh123/p/7405796.html 0x01 CreateProcessW CreateProcess的使用有ANSI版本的Cr ...
- C#委托+回调详解
今天写不完,明天会接着写的,,,, 学习C#有一段时间了,不过C#的委托+回调才这两天才会用,以前只是知道怎么用.前面的一篇文章,函数指针,其实是为这个做铺垫的,说白了委托就相当于C语言中的函数指针, ...
- windows中的进程和线程
今天咱们就聊聊windows中的进程和线程 2016-09-30 在讨论windows下的进程和线程时,我们先回顾下通用操作系统的进程和线程.之所以称之为通用是因为一贯的本科或者其他教材都是这么说的: ...
- [MethodImpl(MethodImplOptions.Synchronized)]、lock(this)与lock(typeof(...))
对于稍微有点经验的.NET开发人员来说,倘若被问及如何保持线程同步,我想很多人都能说好好几种.在众多的线程同步的可选方式中,加锁无疑是最为常用的.如果仅仅是基于方法级别的线程同步,使用System.R ...
- Xamarin.Forms客户端第一版
Xamarin.Forms客户端第一版 作为TerminalMACS的一个子进程模块,目前完成第一版:读取展示手机基本信息.联系人信息.应用程序本地化. 功能简介 详细功能说明 关于TerminalM ...
- [源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块
[源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块 目录 [源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块 0x00 摘要 0x01 前言 0x02 ...
随机推荐
- NSDate的常用用法
1. 创建或初始化可用以下方法 用于创建NSDate实例的类方法有 + (id)date; 返回当前时间 + (id)dateWithTimeIntervalSinceNow:(NSTimeInter ...
- vue中引入jQuery和bootstrap
一.引入jQuery: 首先在当前项目的根目录下(就是与package.json同目录),运行命令npm install jquery --save-dev 这样就将jquery安装到了这个项目中 ...
- java学习总结之文件操作--ByteArrayOutputStream的用法
ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区, 然后利用ByteArrayOutputStream和ByteArrayInputStream ...
- socket编程--相关函数--sendto();read();
{1} 头文件:#include <sys/types.h> #include <sys/socket.h>定义函数:int sendto(int s, const voi ...
- diffMerge安装配置使用
概述: 在用git进行源代码版本维护的时候,常常会进行各代码版本之前区别的查看,例如在每次提交改动前进行git diff 可以看到源文件代码相对相应版本或是远程仓库的改动情况,如果有冲突还需要进行me ...
- mysql-关联查询
MySQL关联查询的三种写法: SELECT * FROM film JOIN film_actor ON (film.film_id = film_actor.film_id);SELECT * F ...
- python_8_字典
什么是字典? --key -value 的数据类型,找到key就可以找到对应的值 --字典形式:{key1:value1,key2:value2,......} #!/usr/bin/python3 ...
- 使用telnet发送HTTP请求
使用telnet发送HTTP请求 写这篇博客,其实没有太大的实际意义,但是还是很有必要的,如果用好Telnet指令,就可以很好的理解HTTP的一些概念,特别是http1.1的持续链接. 要想使用Tel ...
- MyEclipse中导出javadoc文档
1.选中要生成文档的类或者项目→File→Export→Java→Javadoc. 2.在Javadoc command中选择JDK下对应的javadoc.exe:Select types for w ...
- rpm命令的使用
如果服务器配置了本地yum源,大部分的常用软件包都是有的.如果差了头文件或者什么so文件,可以按如下方式找:#以memory.h为例 [root@sz-cdn-centos7-1 tmp]# wher ...