2010-11-16 43 views
9

我意識到我在做什麼可能很愚蠢,但我正在學習WPF,並想知道如何做到這一點。WPF C# - 編輯另一個線程的列表框

我有一個窗口,上面有一個列表框。列表框正在用於在程序運行時傳遞有關程序的狀態消息。例如「服務器啓動」「在IP#的新連接」等我希望這是不斷更新在後臺,所以我產生了一個新的線程處理更新這個,但是當我打電話來添加一個項目,我得到錯誤消息「調用線程不能訪問此對象,因爲不同的線程擁有它。」

任何想法如何我可以從另一個線程更新列表框?或在後臺等。

+5

我太困了,寫一個完整的答案,但這裏有一個提示:環顧四周(Google,SO或MSDN)分派器。現在,我要睡覺了。 – 2010-11-16 04:56:53

回答

24


UPDATE

如果您正在使用C#5和.NET 4.5或以上,你能避免使用asyncawait,獲得在首位另一個線程如:

private async Task<string> SimLongRunningProcessAsync() 
{ 
    await Task.Delay(2000); 
    return "Success"; 
} 

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    button.Content = "Running..."; 
    var result = await SimLongRunningProcessAsync(); 
    button.Content = result; 
} 

簡單:

Dispatcher.BeginInvoke(new Action(delegate() 
    { 
    myListBox.Items.Add("new item")); 
    })); 

如果您處於代碼隱藏狀態。否則,你可以使用訪問調度程序(這是對每一個UIElement):

Application.Current.MainWindow.Dispatcher.BeginInvoke(... 

好的那很多一行讓我過目一下:

當你想更新UI控件你作爲消息說,必須從UI線程中完成。內置的方式可以將委託(方法)傳遞給UI線程:Dispatcher。一旦你有了Dispatcher,你可以通過Invoke()BeginInvoke()傳遞一個委託在UI線程上運行。唯一的區別是Invoke()只會在代理運行後纔會返回(即在你的情況下,列表框的新項目已被添加),而BeginInvoke()將立即返回,以便您的其他線程可以繼續(調度程序將盡快運行您的委託,無論如何它可能會立即運行)。

我通過上述匿名委託:

delegate() {myListBox.Items.Add("new item");} 

之間的{}是該方法塊中的比特。這稱爲匿名,因爲只有一個被創建並且沒有名稱(通常您可以使用lambda表達式執行此操作,但在這種情況下,C#無法解析調用的BeginInvoke()方法)。或者,我可以實例化一個委託:

Action myDelegate = new Action(UpdateListMethod); 

void UpdateListMethod() 
{ 
    myListBox.Items.Add("new item"); 
} 

然後通過了:

Dispatcher.Invoke(myDelegate); 

我還用它內置的委託Action類,但你可以創建你自己 - 你可以讀到更多關於MSDN上的代表,因爲這是一個有點脫離主題..

+0

嘿謝謝,我真的很感謝詳細的解釋!我是一名程序設計專業的學生,​​但我校的每個人都不喜歡C#。我喜歡你的更長時間的解釋,因爲這有助於我理解發生了什麼。 C#和WPF是一門相當龐大的語言,只有我能從書中直接獲得。 – cost 2010-11-16 05:34:30

+0

我的榮幸(這與我給出的另一個答案類似)。請把它標記爲答案如果是:) – markmnl 2010-11-16 06:14:23

+3

我怎麼樣,在這三十年後回頭看,其實我知道一個調度程序,調用,代表,而這一切其他的東西是什麼(其實知道如何使用它! ):) – cost 2013-12-02 19:48:57

2

你會想要使用Dispatcher.BeginInvoke。例如,如果列表框被命名爲listbox

// On worker thread 
    listbox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, 
    new Action(delegate() { listbox.Items.Add("Server started") }); 

這將排隊委託要在UI線程listbox屬於執行。

+0

嘿謝謝,你指出了正確的方向,但編者不喜歡你在這裏給了什麼。給出了關於它如何不能將lamba微積分轉換爲委託的錯誤。我能夠改變它,所以它的工作原理,任何想法是關於你的,或者你只是使用符號我不明白 – cost 2010-11-16 05:28:50

+0

不,我只是懶得檢查自己與一個實際的程序。 – 2010-11-16 12:53:46

5

您還可以使用帶有匿名方法的Action委託從工作線程更新主線程。有關Action類的更多信息,你可以看看這裏:

http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

如果您想更新從多個點,我建議explicitally設置委託列表框,但是如果你只是想在一個更新線程與單一的方法單點調用它可以如下進行:

 listbox.Dispatcher.BeginInvoke(new Action(delegate() 
     { 
      listbox.Items.Add(item); //where item is the item to be added and listbox is the control being updated. 
     })); 

請注意,我用的是Action類,因爲它需要封裝,有一個單獨的參數(在這種情況下,一個ListItem)的方法。

+1

我認爲這樣做。給出的另一個答案給了我一個關於它如何不能將lamba演算轉換爲委託的編譯器錯誤。我在msdn網站上閱讀了一些內容,並搜索瞭如何使用調度程序;我修改了他給我的代碼,結果看起來完全像你在那裏得到的。回答13分鐘前,我應該剛剛刷新,哈哈。 – cost 2010-11-16 05:26:29

相關問題