如何解决DotNET中跨线程访问控件的问题

本文介绍了在DotNET中遇到跨线程访问控件时导致的异常问题,如'线程间操作无效',并提供了两种解决方案:禁用CheckForIllegalCrossThreadCalls属性或使用BeginInvoke方法确保在正确线程中执行操作。示例代码展示了如何在不引发异常的情况下更新TextBox和TreeView控件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如何解决DotNET中跨线程访问控件的问题

                     朱二(2008.10,转载请保留作者)                 

 

如果您对这篇小文感兴趣的话,或许您在编程中时候碰到过以下类似的异常提示:
1、线程间操作无效: 从不是创建控件“X”的线程访问它。(X是控件名称)
2、"在该控件上执行的操作正从错误的线程调用。使用 Control.Invoke 或 Control.BeginInvoke 封送到正确的线程才能执行此操

作。"

看到这种提示,极有可能是跨线程访问控件造成的。举个小例子,窗体FormA上有一位名叫TextBoxA的TextBox大哥。
代码如下:

  1.     Private Sub FormA_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
  2.         Dim th As New System.Threading.Thread(AddressOf CrossThreadCallTest)
  3.         th.Start()
  4.     End Sub
  5.     Public Sub CrossThreadCallTest()
  6.         TextBoxA.Text = "ABC"
  7.     End Sub

简单解释一下:
窗体加载时创建线程th执行过程CrossThreadCallTest,在线程th里面设置TextBoxA的文本。
TextBoxA是主线程创建的,在th线程里访问,造成跨线程访问Windows控件,通常您会得到类似上面的第一个提示。
错误消息如下:
在该控件上执行的操作正从错误的线程调用。使用 Control.Invoke 或 Control.BeginInvoke 封送到正确的线程才能执行此操作。

这样的问题在使用Visual Studio 2003的时候是遭遇不到的,在.NET Framework 2.0中,要想和避免同样的问题,可以采用一个简

单的方法,只要将TextBox类的CheckForIllegalCrossThreadCalls属性设置为False就可以,新代码如下

  1.     Private Sub FormA_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
  2.  TextBox.CheckForIllegalCrossThreadCalls = False
  3.         Dim th As New System.Threading.Thread(AddressOf CrossThreadCallTest)
  4.         th.Start()
  5.     End Sub

但CheckForIllegalCrossThreadCalls并不能解决所有的问题,比如TreeView控件就没有这么幸运,通常会抛出上面第2种提示。并且

对于跨线程访问Windows控件,微软似乎并不推荐使用CheckForIllegalCrossThreadCalls,而推荐采用更为安全的访问技术。
下面这个例子是跨线程向TreeView添加节点的例子:

  1.    Private Sub FormA_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
  2.         Dim th As New System.Threading.Thread(AddressOf CrossThreadCallTest)
  3.         th.Start()
  4.     End Sub
  5.     Public Sub CrossThreadCallTest()
  6.         Dim delAdd As New AddNodeDelegate(AddressOf AddTreeNode)
  7.         TreeView1.BeginInvoke(delAdd)
  8.     End Sub
  9.     Private Delegate Sub AddNodeDelegate()
  10.     Private Sub AddTreeNode()
  11.         TreeView1.Nodes.Add("ABC")
  12.     End Sub

这样一来,AddTreeNode过程还是在主线程里运行,当然不会出现跨线程的问题了,对代码稍加改动,就能说明:

  1.    Private Sub FormA_Load(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles MyBase.Load
  2.         System.Threading.Thread.CurrentThread.Name = "Main"
  3.         Dim th As New System.Threading.Thread(AddressOf CrossThreadCallTest)
  4.         th.Name = "th"
  5.         th.Start()
  6.     End Sub
  7.     Public Sub CrossThreadCallTest()
  8.         Dim delAdd As New AddNodeDelegate(AddressOf AddTreeNode)
  9.         TreeView1.BeginInvoke(delAdd)
  10.     End Sub
  11.     Private Delegate Sub AddNodeDelegate()
  12.     Private Sub AddTreeNode()
  13.         TreeView1.Nodes.Add("ABC")
  14.         '显示的应该是Main
  15.         MessageBox.Show(System.Threading.Thread.CurrentThread.Name)
  16.     End Sub

 

就写这么多,欢迎以评论的形式讨论。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值