【问题标题】: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. 为什么我在尝试阅读列表视图时会收到此信息?我认为跨线程异常是当您尝试从单独的线程更新控件时。

  2. 为什么我也没有得到这个异常?

【问题讨论】:

    标签: c# .net multithreading winforms exception


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

        为什么我也没有得到这个异常?

        没关系,你一开始就不应该这样做。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-07-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多