zoukankan      html  css  js  c++  java
  • 在.Net中进行跨线程的控件操作(上篇:Control.Invoke)

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

    image

    这是由于.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

  • 相关阅读:
    bzoj 1030 [JSOI2007]文本生成器
    Swift 学习笔记 (闭包)
    Swift 学习笔记 (函数)
    HTML 学习笔记 JQueryUI(Interactions,Widgets)
    HTML 学习笔记 JQuery(表单,表格 操作)
    HTML 学习笔记 JQuery(animation)
    HTML 学习笔记 JQuery(盒子操作)
    HTML 学习笔记 JQuery(事件)
    HTML 学习笔记 JQuery(DOM 操作3)
    HTML 学习笔记 JQuery(DOM 操作2)
  • 原文地址:https://www.cnblogs.com/gjhjoy/p/3580526.html
Copyright © 2011-2022 走看看