不一致的“跨线程操作无效”异常

时间:2016-01-14 10:04:53

标签: c# .net multithreading winforms exception

  

跨线程操作无效:从线程访问控制''   除了它创建的线程。

我的同事在我的代码上得到了这个例外,但我不是。

在表单上我有一个控件,用户可以在ListView中添加一些字符串。

我在我的控件中公开了一个属性,它返回XmlDocument中的字符串。

public XmlDocument XmlConfig
{
    get
    {
        return GetXML();
    }
}

获取XML只需获取ListViewItem集合并将它们格式化为xml文档。

private XmlDocument GetXML()
{
    foreach(ListViewItem lvi in myListView.Items)   <-- Exception Here
    {
         // Do Stuff
    }
}
  1. 为什么我在尝试阅读列表视图时会遇到这个问题?我认为跨线程异常是在您尝试从单独的线程更新控件时。

  2. 为什么我也没有得到这个例外?

3 个答案:

答案 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属性或方法调用的控件实现中使用。

  

为什么我也没有得到这个例外?

没关系,你不应该在第一时间这样做。