腾讯微群加入QQ群

 找回密码
 加入我们

!connect_header_login!

!connect_header_login_tip!

搜索
查看: 237|回复: 0

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

[复制链接]
发表于 2016-8-23 13:18:19 | 显示全部楼层 |阅读模式

如何解决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

 

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

0
0

转自:http://blog.csdn.net/netcoder/article/details/3164001?locationNum=7
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

QQ|手机版|Archiver|小黑屋|一起疯|苦咖啡 ( 新ICP备12000197号  

GMT+8, 2018-1-19 05:53 , Processed in 0.112869 second(s), 11 queries , Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表