本文的重点在于介绍如何在多线程编程中,从非UI线程上访问界面中的控件。有过多线程编程经验的人都知道,当我们在非UI线程上试图给一个界面中的控件赋值的时候,比如说label的Text属性,系统会抛出一个下面的异常:

这是由于.Net中的大部分控件的实例都是非线程安全的,如果进行跨线程的访问,可能会造成脏数据,所以.Net默认禁止这种跨线程的赋值操作。那要如何解决这个问题呢?

既然.Net禁止跨线程的赋值操作,那么需要给控件赋值的非UI线程就只有将这种赋值的请求传递给UI线程,最终由UI线程完成赋值的操作。如何传递这种请求?幸运的是,Control类提供了一个Invoke方法。这个方法的功能是将Invoke所指定的方法提交到生成这个Control的UI线程上执行,也就是说我们可以通过调用这个Invoke方法,让UI线程来执行Invoke所指定的方法。 由于Invoke方法是一个public方法,所以所有继承了Control类的.Net控件都可以调用这个方法。

我们来看一下Invoke方法的声明:

   1: public object Invoke(Delegate method);

对于这个Invoke方法,它的参数是一个委托类型,调用的时候指向那个你想让UI线程执行的方法,它的返回值是这个委托指定的方法的返回值。那么如果我想让UI线程执行一个带参数的方法怎么办呢?别着急,Invoke还有另外一个重载方法:

   1: public object Invoke(Delegate method, params object[] args);

这个Invoke方法的参数除了委托类型外,还有一个不定长的参数数组,用来传递委托类型所指定的方法的参数。

有了这两个Invoke方法后,我们在非UI线程中,如果需要给界面中的控件进行赋值操作的话,就可以调用控件的Invoke方法,让Invoke方法去执行给控件进行赋值的操作,这样一来,实际执行给控件赋值的操作就由UI线程执行了。具体过程请参考下面的例子。

   1: private void button1_Click(object sender, EventArgs e)
   2: {
   3:     label1.Text = "开始了";
   4:     Thread newThread = new Thread(new ThreadStart(DoWork));
   5:     newThread.Start();
   6: }
   7:  
   8: public delegate void SampleDelegate(int i);
   9:  
  10: private void DoWork()
  11: {
  12:     for (int i = 0; i < 10; i++)
  13:     {
  14:         System.Threading.Thread.Sleep(1000);
  15:         if (isCancel)
  16:         {
  17:             isCancel = false;
  18:             return;
  19:         }
  20:         SampleDelegate dele = new SampleDelegate(UpdateLabel);
  21:         label1.Invoke(dele, i);
  22:     }
  23: }
  24:  
  25: private void UpdateLabel(int i)
  26: {
  27:     label1.Text = "当前i的值是:" + i.ToString();
  28: }

在上面的例子中,我启动了一个新的线程来执行DoWork,然后我在Label1中不停的刷新DoWork方法中的 i 的值,由于DoWork是在非UI线程执行的,这样我不能直接在DoWork中给Label1.Text赋值,所以,我把赋值操作定义到一个方法UpdateLabel中;然后定义一个委托类型(由于Invoke方法的第一个参数是一个委托类型)并实例化它,让这个委托的实例指向UpdateLabel方法;最后我在DoWork中调用label1.Invoke方法,把执行UpdateLabel的委托提交到UI线程进行执行。这样就完成了整个赋值的操作。

总之,Control.Invoke方法实际上并不是委托的执行者,它仅仅是将委托传递给UI线程,而UI线程才是最终的委托的执行者。所以大家不要被Invoke这个名称所误导,实际上它根本没有执行Invoke操作,仅仅是做了Transfer操作。

最后,请大家仔细想一想,Invoke操作有没有什么风险?(提示:Control可是还提供了BeginInvoke方法哦~~)

来源:http://www.cnblogs.com/happinessCodes/archive/2010/07/19/1780964.html

在.Net中进行跨线程的控件操作(上篇:Control.Invoke)的更多相关文章

  1. 在.Net中进行跨线程的控件操作(下篇:BackgroundWorker)

    在.Net中,如果我们在非UI线程上访问窗体上的控件的时候,会产生一个跨线程调用的异常,那么如何处理这种情况呢?在上一章中,我介绍了使用Control.Invoke方法,如果你不习惯使用委托,那么.N ...

  2. winform跨线程访问控件

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

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

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

  4. C# 跨线程调用控件的4中方法

    原文:C# 跨线程调用控件 在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线 ...

  5. C# 跨线程调用控件

    在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应.  同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁 ...

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

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

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

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

  8. 【转载】C# 跨线程调用控件

    转自:http://www.cnblogs.com/TankXiao/p/3348292.html 感谢原作者,转载以备后用 在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停 ...

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

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

随机推荐

  1. Android获取系统cpu信息,内存,版本,电量等信息

    本文转自:http://www.cnblogs.com/brainy/archive/2012/05/30/2526752.html 1.CPU频率,CPU信息:/proc/cpuinfo和/proc ...

  2. Centos系统创建用户oracle后,用该用户登陆系统,页面加载报错GConf error

    Linux 的 GConf error 解决办法 问题: Centos系统创建用户oracle后,用该用户登陆系统,页面加载报错,导致重新进入Centos系统后出现: GConf error:Fail ...

  3. SDPLR的安装过程(matlab)

    SDPLR 半正定规划优化工具的安装过程很简单,只要按照SDPLR 1.03-beta User's Guide (short version).pdf的介绍安装就可以. 运行在下载的工具包目录里运行 ...

  4. wxWidgets一个界面与数据分离的简单例子

    /*************************************************************** * Name: MyApp.h * Purpose: Defines ...

  5. mkdir、whoami、touch

    mkdir whoami touch:"摸",如果文件不存在,就建立新文件,如果存在,就改变文件的访问时间atime等时间戳信息. mkdir aa ls –ld aa 创建多级目 ...

  6. oracle Imp和exp以及导入常见的错误

    一 1) 数据库对象已经存在 一般情况, 导入数据前应该彻底删除目标数据下的表, 序列, 函数/过程,触发器等; 数据库对象已经存在, 按缺省的imp参数, 则会导入失败 如果用了参数ignore=y ...

  7. bash shell——与if条件相关的参数意义

    最近编写脚本,常看到有 if [ -x $variable ] 类的条件语句,不知道相应参数的意义到底是什么, 特摘录如下:from   http://blog.csdn.net/aaaaatiger ...

  8. Unity3D延迟回调的封装

    最近,整理项目框架逻辑时,无意中翻到n年前封装的延迟回调管理器,就拎出来说道说道: 先说一下系统提供的几种常用的延迟回调方式: 1)Invoke(Invoke.CancelInvoke):首先需要继承 ...

  9. 20169210《Linux内核原理与分析》第十周作业

    第一部分:实验 进程的调度时机与进程的切换 操作系统原理中介绍了大量进程调度算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已. 对于理解操作系统的工作机制 ...

  10. 记录IOS入门的过程

    先说点私话.再进入正题吧,顺便抒发下情绪.公司传统业务不景气,而互联网正如火如荼,无奈被逼上梁山.開始学起了IOS编程.后来想想闲着也是闲着就学习学习呗.无奈公司确实不希望投入了.不愿意提供苹果电脑. ...