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


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

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

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

    示例代码如下: 

    示例代码
    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 方法解决该问题的代码如下:

    使用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 发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。

    推荐阅读:WinForm二三事(三)Control.Invoke&Control.BeginInvoke

    示例代码Invoke_Test

    作者: XuGang   网名:钢钢
    出处: http://xugang.cnblogs.com
    声明: 本文版权归作者和博客园共有!转载时必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    unity3d工具栏介绍
    初识unity3d
    js模拟表单提交
    配置Appium环境
    html单选框 bootstrap模态框里面的单选框 和jq取值
    解决输入框总被浏览器记住的记录遮挡住的问题
    U盘
    python 字典列表/列表套字典 去重重复的字典数据
    ajax把数据return出去
    js把列表转换成字符串
  • 原文地址:https://www.cnblogs.com/stevenjson/p/2454586.html
Copyright © 2020-2023  润新知