在设计界面时,我们经常需要将一些需要时间才能完成的操作放在另一个线程(不同于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. Java知识点:琐碎知识点(2)

    49个关键字一览 abstract default if private this boolean do implements protected throw break double import ...

  2. error: qrc_qml.obj: requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC解决办法

    使用qtcreator加androidndk编译项目时报错: error: qrc_qml.obj: requires unsupported dynamic reloc R_ARM_REL32; r ...

  3. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

  4. LeetCode: pow

    Title: https://leetcode.com/problems/powx-n/ 思路:二分.使用递归或者非递归.非递归有点难理解.pow(0,0)=1 递归的方法是将n为负数的用除法解决.有 ...

  5. Android 下压缩图片—微弱失真

    Android下压缩图片的方法: 大概能将3M左右的图片压缩到100K左右, 几乎不失真. 代码如下: import java.io.FileNotFoundException; import jav ...

  6. 转载RabbitMQ入门(4)--路由

    路由 (使用Java客户端) 在先前的指南中,我们建立了一个简单的日志系统.我们可以将我们的日志信息广播到多个接收者. 在这部分的指南中,我们将要往其中添加一个功能-让仅仅订阅一个消息的子集成为可能. ...

  7. 【转】那些不能错过的Xcode插件 -- 不错不错

    原文网址:http://www.cocoachina.com/industry/20130918/7022.html 古人云“工欲善其事必先利其器”,打造一个强大的开发环境,是立即提升自身战斗力的绝佳 ...

  8. CoreData 基本操作方法封装

    转:http://blog.csdn.net/marujunyy/article/details/18500523 为了方便使用CoreData 封装了几个扩展类,使用方法和类文件如下: //首先需要 ...

  9. 基于Spring AOP实现对外接口的耗时监控

    AOP是Spring的核心,Spring不但自身对多种框架的集成是基于AOP,并且以非常方便的形式暴露给普通使用者.以前用AOP不多,主要是因为它以横截面的方式插入到主流程中,担心导致主流程代码不够清 ...

  10. mybatis+spring+struts2框架整合

     近期公司要开发新的项目,要用struts2+mybatis+spring框架,所以学习了下,来自己的博客发表下,希望能给大家带来帮助!下边我把我的myschool开发的源代码以及数据库贴出来!  开 ...