欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#中Invoke的用法---------多线程操作:线程间操作无效,从不是创建控件的线程访问它

程序员文章站 2022-03-08 22:38:40
...

设计一个界面,点击button之后,改变label的值
实现:点击button执行button的click事件,在函数下创建一个线程change,然后在这个线程中执行改变label的方法ChangeLabel();
C#中Invoke的用法---------多线程操作:线程间操作无效,从不是创建控件的线程访问它
说明:控件是在UI主线程中创建的,进入控件的事件响应函数时,是在控件所在的线程,并不是主线程。在控件的事件响应函数中改变控件的状态,可能与主线程发生线程冲突。
若直接用以下的写法,必然会出错:

 private void btnChange_Click(object sender, EventArgs e)
 {
     Thread Change = new Thread(new ThreadStart(ChangeLabel));
     Change.Name = "zyh";
     Change.Start();
 }
 private void ChangeLabel()
 {
     try
     {
         label.Text = "改变值";
     }
     catch (Exception ex)
     {
         MessageBox.Show(ex.Message,"错误提示",MessageBoxButtons.YesNo,MessageBoxIcon.Error);
     }
 }

C#中Invoke的用法---------多线程操作:线程间操作无效,从不是创建控件的线程访问它

解决方法:

正确的写法是在控件响应函数中调用控件的Invoke方法。Invoke方法会顺着控件向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。正确写法的示例有以下三种:

第一种:

this.Invoke(new Action(() =>
{label.Text = “关闭”; }
));

第二种:

this.Invoke(new Action(
delegate { label.Text = “关闭”; }
));

第三种:

当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它
MSDN中说:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。 如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性 。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。

private void ChangeLabel()
{
try
{
    if (label.InvokeRequired)
    {
        label.Invoke(new MethodInvoker(ChangeLabel));
    }
    else
    {
        label.Text = "改变值";
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message,"错误提示",MessageBoxButtons.YesNo,MessageBoxIcon.Error);
}
}

程序执行:
点击按钮,系统判断,有一个创建label线程以外的线程想访问它,此时InvokeRequired属性为真,调用Invoke方法,在执行一遍ChangeLabel()方法,跳入else中,执行改变label的值,这时候便成功了
C#中Invoke的用法---------多线程操作:线程间操作无效,从不是创建控件的线程访问它
简单的说,如果有两个线程,Thread A和Thread B,并且有一个Control c,是在Thread A里面new的。那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。
相反,如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true。
是否是UI线程与结果无关。(通常Control所在的线程是UI线程,但是可以有例外)
C#中Invoke的用法---------多线程操作:线程间操作无效,从不是创建控件的线程访问它
参考博文:
https://www.cnblogs.com/vaevvaev/p/6909042.html

相关标签: 多线程