2010-11-16 7 views
9

Ich weiß, was ich mache ist wahrscheinlich ziemlich albern, aber ich bin in der Mitte des Lernens WPF und würde gerne wissen, wie das geht.WPF C# - Bearbeiten einer Listbox aus einem anderen Thread

Ich habe ein Fenster mit einer Listbox darauf. Die Listbox wird verwendet, um Statusmeldungen über das Programm zu übermitteln, während es ausgeführt wird. Zum Beispiel "Server gestartet" "Neue Verbindung bei IP #" usw. Ich wollte, dass dies ständig im Hintergrund aktualisiert wird, also habe ich einen neuen Thread für die Handhabung dieser Aktualisierung erzeugt, aber als ich den Anruf zum Hinzufügen eines Elements gemacht habe, bekomme ich die Fehlermeldung "Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da ein anderer Thread es besitzt."

Irgendeine Idee, wie ich die Listbox von einem anderen Thread aktualisieren kann? Oder im Hintergrund usw.

+5

Ich bin zu müde, um eine vollständige Antwort zu schreiben, aber hier ist ein Hinweis: sehen Sie sich um (Google, SO oder MSDN) für Dispatcher. Jetzt gehe ich ins Bett. –

Antwort

24


UPDATE

Wenn Sie C# 5 und .NET 4.5 oder höher Sie in erster Linie auf einem anderen Thread bekommen können vermieden werden, indem unter Verwendung von async und await, zB:

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; 
} 

Einfach:

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

Wenn Sie in Code-Behind sind. Andernfalls können Sie den Dispatcher zugreifen (die auf jeder UIElement ist) mit:

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

Ok das ist eine Menge in einer Zeile lassen Sie mich über sie gehen:

Wenn Sie Sie ein UI-Steuerelement aktualisieren möchten, wie Die Nachricht sagt, muss es aus dem UI-Thread tun. Es gibt eine eingebaute Methode, um einen Delegaten (eine Methode) an den UI-Thread zu übergeben: . Sobald Sie die Dispatcher haben, können Sie entweder Invoke() von BeginInvoke() übergeben einen Delegaten auf dem UI-Thread ausgeführt werden. Der einzige Unterschied ist Invoke() wird nur zurückgegeben, sobald der Delegat ausgeführt wurde (d. H.in Ihrem Fall wurde der neue Eintrag der ListBox hinzugefügt), während BeginInvoke() sofort zurückkehrt, so dass Ihr anderer Thread, von dem Sie anrufen, fortfahren kann (der Dispatcher wird Ihren Delegierten bald ausführen, wie es kann, was wahrscheinlich sowieso sofort sein wird).

I bestanden einen anonymen Delegierten oben:

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

Das Bit zwischen den {} die Verfahrensblock. Dies wird anonym genannt, da nur einer erstellt wird und keinen Namen hat (normalerweise können Sie dies mit einem Lambda-Ausdruck tun, aber in diesem Fall kann C# die aufzurufende BeginInvoke() -Methode nicht auflösen). Oder ich könnte einen Delegaten instanziiert haben:

Action myDelegate = new Action(UpdateListMethod); 

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

Dann ging das:

Dispatcher.Invoke(myDelegate); 

ich auch die Action-Klasse verwendet, die ein in Delegat gebaut, aber Sie könnte Ihre eigene erstellt - Sie können lesen, mehr über Delegaten auf MSDN, da dies ein wenig off topic geht.

+0

Hey danke, ich schätze eine ausführliche Erklärung! Ich bin Programmierstudentin, aber jeder an meiner Schule hat eine Abneigung gegen C#. Ich mag deine längere Erklärung, weil sie mir hilft zu verstehen, was vor sich geht. C# und WPF ist eine ziemlich große Sprache, und es gibt nur so viel, was ich direkt aus einem Buch herausholen kann. – cost

+0

Mein Vergnügen (es ist v. Ähnlich zu einer anderen Antwort, die ich gegeben habe). Pls markieren Sie es als die Antwort, wenn es ist :) – markmnl

+3

Ich mag wie, im Rückblick auf diese drei Jahre später, ich weiß eigentlich, was ein Dispatcher, Aufruf, Delegierte, und all diese anderen Sachen ist (und tatsächlich wissen, wie man es benutzt!) :) – cost

2

Sie möchten Dispatcher.BeginInvoke verwenden. Zum Beispiel wird, wenn die Listbox listbox namens

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

Dies wird den Delegierten Warteschlange bis zu auf dem UI-Thread ausgeführt werden, dass listbox gehört.

+0

Hey danke, du hast in die richtige Richtung gewiesen, aber der Compiler mochte nicht, was du hier gegeben hast. Gab einen Fehler darüber, wie es lamba Kalkül nicht zu einem Delegaten konvertieren kann. Ich konnte es ändern, so dass es funktioniert, jede Idee, was war los mit dir, oder warst du nur Notation, die ich nicht verstehe – cost

+0

Nein, ich war einfach zu faul, mich mit einem tatsächlichen Programm zu überprüfen. –

5

Sie können den Action-Delegaten auch mit anonymen Methoden verwenden, um den Hauptthread aus dem Arbeitsthread zu aktualisieren. Weitere Informationen über die Action-Klasse könnten Sie hier:

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

Wenn Sie das Listenfeld von mehreren Punkten aktualisieren möchten schlage ich explicitally den Delegaten Einstellung, aber wenn Sie nur den Faden auf eine aktualisierenden Single-Point in einem Verfahren mit einem einzigen nennt es getan werden könnte, wie folgt:

 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. 
     })); 

Bitte beachte, dass ich die Action-Klasse verwenden, wie es dauert, kapselt eine Methode, die einen einzelnen Parameter hat (in diesem Fall ein listItem).

+1

Ich denke, das macht es. Die andere Antwort, die gegeben wurde, gab mir einen Compiler-Fehler darüber, wie es das Lamba-Kalkül nicht zu einem Delegaten konvertieren konnte. Ich habe auf der msdn-Site gelesen und gegoogelt, wie man mit dem Dispatcher arbeitet. Ich änderte den Code, den er mir gab, und es stellte sich heraus, dass er genauso aussah wie das, was du da hast. Beantwortete vor 13 Minuten, ich sollte gerade auffrischen, haha. – cost

Verwandte Themen