WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用

Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 Control 线程安全。

在跨线程更新的时候,Control 会检查 CurrentThread 是否为创建 Control 的线程,并报错!

示例代码如下:

示例代码

private void btnStart_Click(object sender, EventArgs e)
{
     //注意:特地不使用 Timer 控件
     Thread thread = new Thread(Fun);
     thread.Start(DateTime.Now.ToString());
}

//报错:线程间操作无效: 从不是创建控件“lblTime”的线程访问它。
private void Fun(object datetime)
{
     lblTime.Text = (string)datetime;
}

最简单的解决方式是在程序代码中添加如下属性:

Control.CheckForIllegalCrossThreadCalls = false;

在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。

将要做的事情放在工作线程中执行,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的。

使用 BeginInvoke 方法解决该问题的代码如下:

使用BeginInvoke方法

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Invoke_Test
{
    public partial class Form1 : Form
    {

//private System.Windows.Forms.Label lblTime;
        //private System.Windows.Forms.Button btnStart;

public Form1()
        {
            InitializeComponent();
            // 解决方式一
            // Control.CheckForIllegalCrossThreadCalls = false;
        }

private void btnStart_Click(object sender, EventArgs e)
        {
            string arg = DateTime.Now.ToString();

// 注意:创建子线程间接调用
            Thread thread = new Thread(FunStart);
            thread.Start(arg); //arg 给方法传参  
        }

// 定义调用方法的委托
        delegate string FunDelegate(string str);

// 注意:特地使用 FunStart 方法模拟间接调用
        private void FunStart(object obj)
        {
            // 要调用的方法的委托
            FunDelegate funDelegate = new FunDelegate(Fun);

/*========================================================
             * 使用this.BeginInvoke方法
             * (也可以使用this.Invoke()方法)
            ========================================================*/

// this.BeginInvoke(被调用的方法的委托,要传递的参数[Object数组])
            IAsyncResult aResult = this.BeginInvoke(funDelegate,obj.ToString());

// 用于等待异步操作完成(-1表示无限期等待)
            aResult.AsyncWaitHandle.WaitOne(-1);

// 使用this.EndInvoke方法获得返回值
            string str = (string)this.EndInvoke(aResult);
            MessageBox.Show(str.ToString());
        }

// 真正需要执行的方法
        private string Fun(string datetime)
        {
            lblTime.Text = (string)datetime;
            return "委托的返回值";
        }
    }
}


Control.InvokeRequired 属性:当前线程不是创建控件的线程时为 true。
也可以认为,在 new Control() 的时候,Control 用一个变量记录下了当前线程,在调用 InvokeRequired 时,返回当前线程是否不等于 new 的时候记录下来的那个线程。

Control.Invoke 和 Control.BeginInvoke 就是“发短信”的方法,如果使用 Control.Invoke 发短信,那么甲线程就会像个痴情的汉子,一直等待着乙线程的回音,而如果使用 Control.BeginInvoke 发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。

推荐阅读:WinForm二三事(三)Control.Invoke&Control.BeginInvoke

示例代码:Invoke_Test

WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用 Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 C相关推荐

  1. This.invoke和this.begininvoke的区别?

    ①个人总结:This.begininvoke和this.invoke委托调用的方法都是在UI线程中执行. This.begininvoke和this.invoke 匿名委托这个代码是注册委托的,然后等 ...

  2. C#窗体中Invoke和BeginInvoke方法详解

    在 Invoke 或者 BeginInvoke 的使用中无一例外地使用了委托 Delegate ,至于委托的本 质请 参考 我的另一随笔: 对 .net 事件的看法 . 一. 为 什 么 Contro ...

  3. (转)C# Delegate.Invoke、Delegate.BeginInvoke

    Delegate的Invoke.BeginInvoke 1.Delegate.Invoke (委托同步调用) a.委托的Invoke方法,在当前线程中执行委托. b.委托执行时阻塞当前线程,知道委托执 ...

  4. Mcad学习笔记之异步编程(AsyncCallback委托,IAsyncResult接口,BeginInvoke方法,EndInvoke方法的使用小总结)...

    收藏地址  http://aierong.cnblogs.com/archive/2005/05/25/162308.html 让我们来看看同步异步的区别: 同步方法调用在程序继续执行之前需要等待同步 ...

  5. 论文理解【RL - Episodic Control】 ——【MFEC】Model Free Episodic Control

    标题:Model Free Episodic Control 文章链接:Model Free Episodic Control 代码实现:sudeepraja Model-Free-Episodic- ...

  6. Winform获取应用程序的当前路径的方法集合,具体如下,值得收藏

    Winform获取应用程序的当前路径的方法集合,具体如下,值得收藏//获取当前进程的完整路径,包含文件名(进程名). string str = this.GetType().Assembly.Loca ...

  7. winform频繁刷新导致界面闪烁解决方法

    winform频繁刷新导致界面闪烁解决方法 参考文章: (1)winform频繁刷新导致界面闪烁解决方法 (2)https://www.cnblogs.com/arxive/p/6270007.htm ...

  8. C#Winform频繁刷新导致界面闪烁解决方法

    C#Winform频繁刷新导致界面闪烁解决方法 参考文章: (1)C#Winform频繁刷新导致界面闪烁解决方法 (2)https://www.cnblogs.com/ghbjimmy/article ...

  9. com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法

    com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法 参考文章: (1)com.alibaba.dubbo.rp ...

最新文章

  1. 如果政府强制开发linux应用,Linux开发环境及应用-中国大学mooc-题库零氪
  2. LeetCode-175. 组合两个表(SQL语句中的LEFT JOIN)
  3. 获得分辨率_变分辨率宽幅面光固化3D打印,
  4. 美图影像节发布六款新品 满足用户生活、工作全方位变美需求
  5. 前端周记20190211-20190215
  6. 【weiphp微信开发教程】留言板插件开发详解
  7. [转载]Mysql导出表结构及表数据 mysqldump用法
  8. Python 2.7.5 CentOS 6.4 编译 错误
  9. 使用lkjson处理Json数据
  10. 贝叶斯优化混合核极限学习机回归预测
  11. C++ DNF脚本源码模板开源
  12. 如何保存android app日志(转载)
  13. 重装win10系统后不能上网如何解决?
  14. 【开发指南】Spring Cloud集成POI完成Excel读写操作
  15. 分布式-分布式常见问题和解决方案
  16. 机电一体化仿真--手爪
  17. Android之获取地理位置
  18. LARS回归算法的几何意义
  19. 前端自动化测试(webdriverio+mocha+chai)
  20. 工具变量:顶刊中的Shock-IV整理

热门文章

  1. python学习-列表解析、字典解析
  2. 大数据中常见的端口号 总结汇总大全(最新)
  3. android工程引入unity,Unity导出Android Studio工程
  4. nexus 仓库类型_使用Nexus私服代理其他maven仓库(jitpack、jcenter)
  5. oracle自动把SID给改了,Oracle SID修改方式的详解
  6. android queue用法,GitHub - rygz146/TQueue: Android 可以任意切换线程的任务队列, TQueue
  7. 嵌入式大牛常用的十大C/C++开发利器
  8. 访问 GitHub 的速度很慢?试试这几种方法
  9. 经常遇到的10大C语言基础算法(珍藏版源码)
  10. 硬件工程师前途到底怎样?看看大佬怎么说,看完跪了