C#之Winform跨线程访问控件

C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它。此时它将会在内部调用new MethodInvoker(LoadGlobalImage)来完成下面的步骤,这个做法保证了控件的安全,你可以这样理解,有人想找你借钱,他可以直接在你的钱包中拿,这样太不安全,因此必须让别人先要告诉你,你再从自己的钱包把钱拿出来借给别人,这样就安全了

----------------------------------------------------------------------

在设计中为了让界面与逻辑分离,我的做法是使用事件,界面只要响应事件来处理界面的显示就行了。而事件在逻辑处理中可能由不同的线程引发,这些事件的响应方法在修改界面中的控件内容时便会引发一个异常。

这时就用到了Control.InvokeRequired 属性 与Invoke方法。

------------------------------------------------------------------------

获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。

如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。

Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性 。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。

 private   delegate   void  InvokeCallback( string  msg);
void  m_comm_MessageEvent( string  msg)
    {
     if (txtMessage.InvokeRequired)
     {
     InvokeCallback msgCallback  =   new  InvokeCallback(m_comm_MessageEvent);
     txtMessage.Invoke(msgCallback,  new   object []  { msg } );
    }
     else
     {
     txtMessage.Text  =  msg;
    }
   }

说明:这个函数就是事件处理函数,txtMessage是一个文本框。

这样就做到了窗体中控件的线程安全性。

------------------------------------------------------------------------

InvokeRequired 当前线程不是创建控件的线程时为true

比如你可以自己开一个Thread,或使用Timer的事件来访问窗体上的控件的时候,在线程中窗体的这个属性就是True的。

简单的说,如果有两个线程,Thread A和Thread B,并且有一个Control c,是在Thread A里面new的。

那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。

相反,如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true。

是否是UI线程与结果无关。(通常Control所在的线程是UI线程,但是可以有例外)

也可以认为,在new Control()的时候,control用一个变量记录下了当前线程,在调用InvokeRequired时,返回当前线程是否不等于new的时候记录下来的那个线程。

时间: 2024-10-27 07:56:11

C#之Winform跨线程访问控件的相关文章

WinForm跨线程访问控件异常

WinForm跨线程访问控件异常 最近做了个WinForm的小项目,遇到个简单的问题记录下.需求:点击"下载",显示正在下载,下载完后更新状态为"ready"(要求用多线程,避免前台卡死). 做法 新建一个线程,在新线程中下在更新控件状态,报异常跨线程程访问控件(当然可以通过关闭跨线程访问控件检验解决,不鼓励这么做).应该C#5.0版本添加的任务Task异步,这里用异步解决. Code 新建WinForm 项目,Form1添加控件如图 后台代码 private vo

winform 跨线程访问控件

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 {

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

功能函数测试集锦(77)  C#专区(114)  版权声明:本文为博主原创文章,未经博主允许不得转载. .net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生,有一种方法是禁止编译器对跨线程访问作检查,Control.CheckForIllegalCrossThreadCalls = false;可以实现访问,但是出不出错不敢保证C#跨线程访问控件运行时错误. 使用MethodInvoker即可解决: 原代码: private void btnOK_Click(object sender

2 跨线程访问控件InvokeHelper类

这里是一张动画,演示在多线程(无限循环+Thread.Sleep)情况下主界面操作不受影响. 多线程是一种提高程序运行效率和性能的常用技术.随着我们学习工作的深入,在编程中或多或少会涉及到需要多线程的情况.多数时候,我们的操作模式是后台线程中处理数据,计算结果,然后在前台界面(GUI)中更新显示. 在.NET Framework中,为了保证线程安全,避免出现访问竞争等问题,是不允许跨线程访问窗体控件的.如果强行访问,则会引发InvalidOperationException无效操作异常,如下图:

C# WinFrom 跨线程访问控件

1.跨线程访问控件委托和类的定义 using System; using System.Windows.Forms; namespace ahwildlife.Utils { /// <summary> /// 跨线程访问控件的委托 /// </summary> public delegate void InvokeDelegate(); /// <summary> /// 跨线程访问控件类 /// </summary> public class Invok

跨线程访问控件的问题和编程方法

很多时候写windows程序都需要结合多线程,经常会跨线程操作控件,这时就会出错,提示不允许"从不是创建控件的进程访问它". 这个时候的解决思路:把想对另一线程中的控件实施的操作放到一个函数中,然后使用delegate代理那个函数,并且在那个函数中加入一个判断,用InvokeRequired来判断调用这个函数的线程是否和控件线程在同一线程中,如果是则直接执行对控件的操作,否则利用控件的Invoke或BeginInvoke方法来执行这个代理,执行唤醒控件的操作.Invoke的中文解释是唤

Winform之跨线程访问控件(在进度条上显示字体)

此文章对于遇到必须使用线程但是没有办法在线程内操作控件的问题的处理  有很好的解决方案(个人认为的.有更好的方案欢迎交流.) 在做跨线程访问之前我们先了解下我们所做的需要达到的效果: 这个是批量的将xml文件导入sqlite数据库   每个xml有将近3000的节点  每个节点有5个属性,如果我们不用线程那么在数据导入的过程中   程序很可能卡死   而且基本上动不了,用户的体验性就很差. 所以我们对向数据库添加数据的地方使用了线程: Thread thread = new Thread(new

跨线程访问控件的方法

主窗体创建的控件相当于主线程管理,在分线程使用的时候会产生跨线程访问的问题,这时需要如下判断写法,即可解决 if (lblNum2.InvokeRequired) { lblNum2.Invoke(new Action<string>(s => { this.lblNum2.Text = s; }), Thread.CurrentThread.ManagedThreadId.ToString()); } else { this.lblNum2.Text = Guid.NewGuid().

跨线程访问控件解决办法

在多线程中访问控件有两种方式 方式1: 取消对跨线程操作的检查 在 from 的构造 函数中增加 system.window.forms.control.CheckForIllegalCrossThreadCalls=false; 方式2 : 采用委托的形式作为代理通知主线程控件,允许访问. delegate void   showData(string para); visistControl(string para) { if (this.textbox1.invokeRequered) /