2016-01-14 85 views
1

跨線程操作無效:從線程 以外的線程訪問的控制「',而不是線程的創建。不一致的「跨線程操作無效」異常

我的同事在我的代碼上得到這個異常,但我不是。

在窗體上我有一個控件,用戶可以在其中添加一些字符串到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. 爲什麼我沒有得到這個例外呢?

回答

4

我以爲橫紗的例外是當你試圖更新從一個單獨的線程控制

不正確。當控件從不是主UI線程的訪問時發生跨線程異常。解決方案很簡單,請檢查InvokeRequired並使用Invoke。至於爲什麼你的朋友打這個,你不這樣做,從你發佈的代碼是不可能告訴你的。這可能是他針對不同的.Net目標版本編譯的,或者它可能是一個競爭條件,即你的硬件受到了打擊(例如,他擁有更多內核)。重點是無關緊要的。你的代碼需要線程安全,因爲顯然GetXML can和從非主UI線程調用。檢查InvokeRequired的責任很可能是調用者,而不是方法。再次,從發佈的代碼是不可能的。

2

當其他訪問ControlUI線程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(); 
    } 
    } 
0

我以爲跨線程異常是當你試圖從一個單獨的線程更新控件。

這是不正確的。請記住,大多數WinForms控件都是圍繞Windows常用控件的包裝。和Windows控件使用消息檢索和更新,通常通過SendMessage function。因此,一般來說,儘管某些調用可能會安全地從另一個線程執行,但出於安全原因,Control.CheckForIllegalCrossThreadCalls用於每個get/set屬性或方法調用的控件實現。

爲什麼我沒有得到這個例外呢?

沒關係,你不應該這樣做的第一個地方。