在设计界面时,我们经常需要将一些需要时间才能完成的操作放在另一个线程(不同于UI主线程)中执行。但是这些操作可能需要将其结果或完成情况通知主线程,比如调用窗体的方法,或者触发事件(由界面响应事件),很多情况下这种通知需要访问控件。
但是如果调用上述方法或者触发事件的线程不是控件的创建进程,Control就不能在创建它的thread之外被访问,此时会引发一个异常,好在可以通过控件的invoke方法来访问它。
Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的 Invoke 方法来将调用封送到适当的线程。
 
一、 Control.InvokeRequired 属性与 Invoke方法
 
Control.InvokeRequired 属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。MSDN中将其解释为“获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。
事实上,Control.InvokeRequired返回的结果就是 CurrentThread != ControlCreatThread 而已,在创建者线程和其它线程中,该值不同。
 
比较好的做法如下:
 
首先定义一个与可能被控件的非创建线程调用的方法或者事件处理函数的签名一样委托,如:
private  delegate  void  DeleUpdateText ( string  text );
 
当然直接使用已有的事件的委托也是可以的。
 
然后就是判断这个属性的值来决定是否要调用Invoke函数:
private  void  UpdateText ( string  text )
{
    if(this.InvokeRequired)
    {
        this.Invoke( new  DeleUpdateText( UpdateText ),  new  object[]{text} );
    }
    else
    {
        MyTextBox.Text   =  text;
    }
}
 
需要说明的:
1. Control.Invoke方法的第二个参数为 object[] 类型,作为指定方法的参数传递的对象数组。如果此方法没有参数,该参数可以是 null,或者使用不含该参数的重载版本。
2. 方法返回值的类型为 Object ,它包含正被调用的委托返回值;如果该委托没有返回值,则为 null。
 
二、BeginInvoke 方法
 
使用 Invoke 方法调用委托,在所委托的方法执行完成前,会阻塞进程,另一个更好的选择是异步调用委托的BeginInvoke方法,这个方法总是不等待委托的执行而立刻放回,特别适合于调用后就不用再管的方法执行。当然,也可以使用其返回的IAsyncResult类型的结果,并和委托的 EndInvoke 方法一起使用,以在该方法调用完毕后检索调用结果。
 
其参数和 Invoke 方法类似:
 
// Created on UI thread, but doesn't run on UI thread
private Label lblStatus;
{
    DoSomethingSlow();
    // Do UI update on UI thread
    object[] pList = { this, System.EventArgs.Empty };
    lblStatus.BeginInvoke( new System.EventHandler(UpdateUI), pList); }
    •••
    // Code to be run back on the UI thread
    // (using System.EventHandler signature, 
    // so we don't need to define a new delegate type here)
    private void UpdateUI(object o, System.EventArgs e)
    {
        // Now OK - this method will be called via Control.Invoke, 
        // so we are allowed to do things to the UI.
        lblStatus.Text = "Finished!";
    }
}
 
关于这个问题,发现了一篇讲解的特别清晰透彻的文章(作者:Ian Griffiths),附上原文和译文的名称和链接。似乎中英文版本的图片和代码都有些问题,在搜索引擎上直接搜索文章名或许可以找到排版更好的版本。
 
Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads
 
通过多线程为基于 .NET 的应用程序实现响应迅速的用户

[C#] Control.Invoke方法和跨线程访问控件的更多相关文章

  1. [C#] Control.Invoke方法和跨线程访问控件(转载)

    转载前,在网上找了好多INVOKE方法的文章,就这个看着还可以,明白了大概,以后再深用的时候再研究 ,废话少说上转载(连转载都说的这么有气势,哈哈)   在设计界面时,我们经常需要将一些需要时间才能完 ...

  2. C# WinFrom 跨线程访问控件

    1.跨线程访问控件委托和类的定义 using System; using System.Windows.Forms; namespace ahwildlife.Utils { /// <summ ...

  3. winform跨线程访问控件

    首先说下,.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性.所以除了控件所在的线程外的线程调用会抛异常 (Cross-thread operation not va ...

  4. c#使用MethodInvoker解决跨线程访问控件

      功能函数测试集锦(77)  C#专区(114)  版权声明:本文为博主原创文章,未经博主允许不得转载. .net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生,有一种方法是禁止编译器对跨线 ...

  5. C# 关于跨线程访问控件问题

    跨线程访问控件问题的原因是:控件都是在主线程中创建的,而系统默认控件的修改权归其创建线程所有.在子线程中如果需要直接修改控件的内容,需要使用委托机制将控件的修改操作交给主线程处理.因此,当没有使用委托 ...

  6. C# 跨线程访问控件(MethodInvoker)

    参考:https://www.cnblogs.com/lvdongjie/p/5428815.html .Net 通常禁止跨线程访问控件,设置Control.CheckForIllegalCrossT ...

  7. c#跨线程访问控件帮助类

    1.背景 对于winform程序来说,当我们点击按钮,需要消耗一定时长才能拿到数据后才能显示在界面上某个控件上的情况,我们通常会专门开一个线程去拿数据,这样不会造成界面处于假死状态 2.常规做法 // ...

  8. c# winform InvokeRequired 解决跨线程访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它. Windows 窗体中 ...

  9. C#之Winform跨线程访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...

随机推荐

  1. I.MX6 linux Qt 同时支持Touch、mouse

    /***************************************************************************** * I.MX6 linux Qt 同时支持 ...

  2. Android service binder aidl 关系

    /********************************************************************************** * Android servic ...

  3. (function(){})()这个是什么?有不明觉厉的感觉么?

    今天在RunJs上看到一个人分享的一个jquery代码,写的是jquery弹性滑动效果.不过,看着看着,发现一句代码(function{})(),突然有种不明觉厉的感觉. 事实上,只是因为我们没有用过 ...

  4. [Everyday Mathematics]20150109

    设 $A$ 是 $n$ 阶复方阵, 其特征多项式为 $$\bex f(\lm)=(\lm-\lm_1)^{n_1}\cdots(x-\lm_s)^{n_s}, \eex$$ 其中 $\lm_i$ 互不 ...

  5. 自定义TreeList单元格 z

    DevExpress Treelist自定义单元格,加注释和行序号.以上一节的列表为例,实现以下效果:预算大于110万的单元格突出显示,加上行序号以及注释,如下图: 添加行序号要用到CustomDra ...

  6. Java连接Sql Server2008

    参考:http://weistar.iteye.com/blog/1744871 准备工作: 1.下载JDBC驱动包:http://www.microsoft.com/zh-cn/download/d ...

  7. 微信web调试工具

    做微信公众号开发的时候,最头疼的一件事,莫过于bug调试了. 由于有些功能涉及到权限问题,必须在微信公众号内打开,所以对开发人员来说就是遇到了一场噩梦. 这里有两种方法: 1.工具:mac.使用微信m ...

  8. CentOS6 搭建git

    rpm -qa | grep zlib-devel  查看是否安装过 ----------------------------------------------------------------- ...

  9. Activating Google Cloud Storage

    先决条件 你需要下面的内容: 1.一个Google账户,比如来自Gmail.如果你没有,请在Google account signup site注册. 2.一个新的或已经存在的Google Devel ...

  10. 基于Node.js的实时推送 juggernaut

    基于Node.js的实时推送 juggernaut Juggernaut 基于 Node.js 构建.为浏览器和服务器端提供一个实时的连接,可在客户端和服务器端进行数据的实时推送,适合多角色游戏.聊天 ...