跨线程操作无效:从线程访问控制'' 除了它创建的线程。
我的同事在我的代码上得到了这个例外,但我不是。
在表单上我有一个控件,用户可以在ListView中添加一些字符串。
我在我的控件中公开了一个属性,它返回XmlDocument中的字符串。
public XmlDocument XmlConfig
{
get
{
return GetXML();
}
}
获取XML只需获取ListViewItem集合并将它们格式化为xml文档。
private XmlDocument GetXML()
{
foreach(ListViewItem lvi in myListView.Items) <-- Exception Here
{
// Do Stuff
}
}
为什么我在尝试阅读列表视图时会遇到这个问题?我认为跨线程异常是在您尝试从单独的线程更新控件时。
为什么我也没有得到这个例外?
答案 0 :(得分:4)
我认为跨线程异常是在您尝试从单独的线程更新控件时
不正确。从主UI线程访问控件时会发生跨线程异常。该解决方案非常简单,请检查InvokeRequired
并使用Invoke
。
至于为什么你的朋友点击这个而你没有,你不可能从你发布的代码中说出来。可能是他针对不同的.Net目标版本进行编译,或者它可能是您的硬件受到攻击的竞争条件(例如,他有更多核心)。点是无关紧要的。您的代码需要是线程安全的,因为显然GetXML
可以从非主UI线程调用 。检查InvokeRequired
的责任可能是调用者,而不是方法。再一次,从发布的代码中无法分辨出来。
答案 1 :(得分:2)
在 UI线程(Control
返回InvokeRequired
)之外访问true
时,您应该使用Invoke
而不是直接调用;为了不复制代码(对于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();
}
}
答案 2 :(得分:0)
我认为跨线程异常是在您尝试从单独的线程更新控件时。
这不正确。请记住,大多数WinForms控件都是围绕Windows常用控件的包装器。 Windows控件使用消息进行检索并通常通过SendMessage function进行更新。所以一般来说,虽然某些调用可以安全地从另一个线程执行,但出于安全原因Control.CheckForIllegalCrossThreadCalls在每个get / set属性或方法调用的控件实现中使用。
为什么我也没有得到这个例外?
没关系,你不应该在第一时间这样做。