不一致的“跨线程操作无效”异常
Posted
技术标签:
【中文标题】不一致的“跨线程操作无效”异常【英文标题】:Inconsistent "Cross-thread operation not valid" exception 【发布时间】:2016-04-19 14:31:53 【问题描述】:跨线程操作无效:控制''从线程访问 除了创建它的线程之外。
我的同事在我的代码中遇到了这个异常,但我没有。
在表单上,我有一个控件,用户可以在其中向 ListView 添加一些字符串。
我在控件中公开了一个属性,该属性返回 XmlDocument 中的字符串。
public XmlDocument XmlConfig
get
return GetXML();
Get XML 只是获取 ListViewItem 集合并将它们格式化为 xml 文档。
private XmlDocument GetXML()
foreach(ListViewItem lvi in myListView.Items) <-- Exception Here
// Do Stuff
为什么我在尝试阅读列表视图时会收到此信息?我认为跨线程异常是当您尝试从单独的线程更新控件时。
为什么我也没有得到这个异常?
【问题讨论】:
【参考方案1】:我认为跨线程异常是当您尝试从单独的线程更新控件时
不正确。当控件不是从主 UI 线程访问时会发生跨线程异常。解决方法很简单,检查InvokeRequired
并使用Invoke
。
至于为什么您的朋友点击了这个而您没有点击,从您发布的代码中无法判断。可能是他针对不同的 .Net 目标版本进行编译,或者可能是您的硬件未命中的竞争条件(例如,他有更多内核)。重点是这无关紧要。您的代码需要是线程安全的,因为显然 GetXML
可以并且 is 从非主 UI 线程调用。检查InvokeRequired
的责任很可能在于调用者,而不是方法。同样,从发布的代码中无法分辨。
【讨论】:
【参考方案2】:当在 UI 线程 之外访问Control
时(InvokeRequired
返回true
),您应该使用Invoke
insetead 直接调用;为了不重复代码(对于 UI 线程和其他线程),让我们使用扩展方法:
private XmlDocument GetXML()
myListView.InvokeSynchronized(() =>
foreach(ListViewItem lvi in myListView.Items)
// Do Stuff
);
...
public static class ControlAsyncExtensions
public static void InvokeSynchronized(this Control control, Action action)
if (Object.ReferenceEquals(null, action))
throw new ArgumentNullException("action");
if (Object.ReferenceEquals(null, control))
action();
else if (control.InvokeRequired)
control.Invoke(action);
else
action();
【讨论】:
【参考方案3】:我认为跨线程异常是在您尝试从单独的线程更新控件时发生的。
这是不正确的。请记住,大多数 WinForms 控件都是围绕 Windows 通用控件的包装器。 Windows 控件使用 messages 进行 检索 和更新,通常通过 SendMessage function。所以一般来说,虽然 一些 调用可以安全地从另一个线程执行,但出于安全原因,Control.CheckForIllegalCrossThreadCalls 用于每个 get/set 属性或方法调用的控件实现中。
为什么我也没有得到这个异常?
没关系,你一开始就不应该这样做。
【讨论】:
以上是关于不一致的“跨线程操作无效”异常的主要内容,如果未能解决你的问题,请参考以下文章
例外:跨线程操作无效:控制'pgImportProcess(进度条)'从一个线程访问,而不是它在[重复]上创建的线程