0
点赞
收藏
分享

微信扫一扫

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


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

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

示例代码如下: 

WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用_示例代码WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用_DotNet_02示例代码 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 方法解决该问题的代码如下:

WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用_示例代码WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用_DotNet_02使用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 发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。


示例代码:Invoke_Test

举报

相关推荐

0 条评论