簡體   English   中英

不一致的“跨線程操作無效”異常

[英]Inconsistent “Cross-thread operation not valid” 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. 為什么我也沒有得到這個例外?

我以為跨線程異常是當您嘗試從單獨的線程更新控件時

不對。 當不是從主UI線程訪問控件時,就會發生跨線程異常。 解決方案很簡單,請檢查InvokeRequired並使用Invoke

至於為什么你的朋友打了這個而你卻不打呢,這不可能從你發布的代碼中看出來。 可能是他針對不同的.Net目標版本進行了編譯,也可能是您的硬件受到打擊的競爭條件(例如,他擁有更多的內核)。 一點是無關緊要的。 您的代碼必須是線程安全的,顯然GetXML可以並且從非主UI線程調用的。 檢查InvokeRequired的責任很可能應該在調用方上,而不是在方法上。 同樣,從發布的代碼中無法分辨。

當在非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();
    }
  }

我以為跨線程異常是當您嘗試從單獨的線程更新控件時。

那是不對的。 請記住,大多數WinForms控件都是Windows通用控件的包裝 Windows控件通常通過SendMessage函數消息用於檢索和更新。 因此,通常來說,盡管可以安全地從其他線程執行某些調用,但是出於安全原因, Control.CheckForIllegalCrossThreadCalls用於每個get / set屬性或方法調用的控件實現中。

為什么我也沒有得到這個例外?

沒關系,您不應該一開始就這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM