Ich soll auf den Dispatcher zugreifen können, der zur Ansicht gehört. Ich muss ihn an das ViewModel übergeben. Die Ansicht sollte jedoch nichts über das ViewModel wissen. Wie können Sie es weitergeben? Führen Sie eine Schnittstelle ein oder erstellen Sie einen globalen Dispatcher-Singleton, der von der Ansicht geschrieben wird, anstatt ihn an die Instanzen zu übergeben. Wie lösen Sie dies in Ihren MVVM-Anwendungen und Frameworks?
BEARBEITEN: Da meine ViewModels möglicherweise in Hintergrundthreads erstellt werden, kann ich dies nicht einfach Dispatcher.Current
im Konstruktor des ViewModels tun .
quelle
warum würdest du nicht benutzen
anstatt den Verweis auf den GUI-Dispatcher beizubehalten.
quelle
Möglicherweise benötigen Sie den Dispatcher nicht. Wenn Sie Eigenschaften Ihres Ansichtsmodells an GUI-Elemente in Ihrer Ansicht binden, führt der WPF-Bindungsmechanismus die GUI-Aktualisierungen mithilfe des Dispatchers automatisch an den GUI-Thread weiter.
BEARBEITEN:
Diese Bearbeitung ist eine Antwort auf Isak Savos Kommentar.
Im Microsoft-Code zur Behandlung der Bindung an Eigenschaften finden Sie den folgenden Code:
Dieser Code führt alle UI-Aktualisierungen des Thread-UI-Threads durch, sodass WPF den Aufruf des UI-Threads automatisch serialisiert, selbst wenn Sie die Eigenschaften aktualisieren, die an der Bindung eines anderen Threads beteiligt sind.
quelle
Ich erhalte das ViewModel, um den aktuellen Dispatcher als Mitglied zu speichern.
Wenn das ViewModel von der Ansicht erstellt wird, wissen Sie, dass der aktuelle Dispatcher zum Zeitpunkt der Erstellung der Dispatcher der Ansicht ist.
quelle
Ab MVVM Light 5.2 enthält die Bibliothek jetzt eine
DispatcherHelper
Klasse imGalaSoft.MvvmLight.Threading
Namespace, die eine Funktion verfügbar machtCheckBeginInvokeOnUI()
, die einen Delegaten akzeptiert und auf dem UI-Thread ausführt. Dies ist sehr praktisch, wenn in Ihrem ViewModel einige Arbeitsthreads ausgeführt werden, die sich auf die VM-Eigenschaften auswirken, an die Ihre UI-Elemente gebunden sind.DispatcherHelper
muss initialisiert werden, indem SieDispatcherHelper.Initialize()
frühzeitig im Leben Ihrer Anwendung anrufen (zApp_Startup
. B. ). Sie können dann einen beliebigen Delegaten (oder Lambda) mit dem folgenden Aufruf ausführen:Beachten Sie, dass die Klasse in einer
GalaSoft.MvvmLight.Platform
Bibliothek definiert ist, auf die standardmäßig nicht verwiesen wird, wenn Sie sie über NuGet hinzufügen. Sie müssen manuell einen Verweis auf diese Bibliothek hinzufügen.quelle
Ein weiteres gängiges Muster (das derzeit im Framework häufig verwendet wird) ist der SynchronizationContext .
Sie können damit synchron und asynchron versenden. Sie können auch den aktuellen SynchronizationContext für den aktuellen Thread festlegen, sodass er leicht verspottet werden kann. Der DispatcherSynchronizationContext wird von WPF-Apps verwendet. Andere Implementierungen des SynchronizationContext werden von WCF und WF4 verwendet.
quelle
Ab WPF Version 4.5 kann CurrentDispatcher verwendet werden
quelle
Wenn Sie den Dispatcher nur zum Ändern einer gebundenen Sammlung in einem anderen Thread benötigen, sehen Sie sich die SynchronizationContextCollection hier an: http://kentb.blogspot.com/2008/01/cross-thread-collection-binding-in-wpf.html
Funktioniert gut. Das einzige Problem, das ich festgestellt habe, ist die Verwendung von Ansichtsmodellen mit SynchronizationContextCollection-Eigenschaften mit ASP.NET-Synchronisierungskontext.
HTH Sam
quelle
Hallo, vielleicht bin ich zu spät, da seit deinem ersten Beitrag 8 Monate vergangen sind ... Ich hatte das gleiche Problem in einer Silverlight-MVVM-Anwendung. und ich fand meine Lösung so. Für jedes Modell und Ansichtsmodell, das ich habe, habe ich auch eine Klasse namens Controller. so wie das
Mein MainController ist für den Befehl und die Verbindung zwischen Modell und Ansichtsmodell verantwortlich. Im Konstruktor instanziiere ich die Ansicht und ihr Ansichtsmodell und setze den Datenkontext der Ansicht auf ihr Ansichtsmodell.
// (in meiner Namenskonvention habe ich ein Präfix m für Mitgliedsvariablen)
Ich habe auch eine öffentliche Eigenschaft in der Art meiner MainView. so wie das
(Diese mMainView ist eine lokale Variable für das öffentliche Eigentum.)
und jetzt bin ich fertig. Ich muss nur meinen Dispatcher für meine Benutzeroberfläche verwenden ...
(In diesem Beispiel habe ich meinen Controller gebeten, meinen Sharepoint 2010-Loginnamen zu erhalten, aber Sie können tun, was Sie brauchen.)
Wir sind fast fertig. Sie müssen auch Ihr Root-Visual in der app.xaml so definieren
Das hat mir durch meine Bewerbung geholfen. Vielleicht kann es dir auch helfen ...
quelle
Sie müssen den UI-Dispatcher nicht an das ViewModel übergeben. Der UI-Dispatcher ist im aktuellen Anwendungs-Singleton verfügbar.
Dadurch wird Ihr ViewModel von der Ansicht abhängig. Abhängig von Ihrer Anwendung kann dies in Ordnung sein oder auch nicht.
quelle
Verwenden Sie für WPF- und Windows Store-Apps: -
Es ist nicht wirklich der richtige Weg, auf den GUI-Dispatcher zu verweisen.
Wenn dies nicht funktioniert (z. B. bei Windows Phone 8-Apps), verwenden Sie: -
quelle
Wenn Sie uNhAddIns verwenden, können Sie leicht ein asynchrones Verhalten erzeugen . Schauen Sie hier
Und ich denke, ich brauche ein paar Modifikationen, damit es auf Castle Windsor funktioniert (ohne uNhAddIns).
quelle
Ich habe einen anderen (einfachsten) Weg gefunden:
Hinzufügen, um Modellaktion anzuzeigen, die im Dispatcher aufgerufen werden soll:
public class MyViewModel { public Action<Action> CallWithDispatcher; public void SomeMultithreadMethod() { if(CallWithDispatcher != null) CallWithDispatcher(() => DoSomethingMetod(SomeParameters)); } }
Fügen Sie diesen Aktionshandler im Ansichtskonstruktor hinzu:
Jetzt haben Sie keine Probleme mit dem Testen und es ist einfach zu implementieren. Ich habe es meiner Seite hinzugefügt
quelle
Sie müssen den Dispatcher nicht übergeben, wenn Sie mit auf den Anwendungs-Dispatcher zugreifen können
quelle
Bei einigen meiner WPF-Projekte war ich mit der gleichen Situation konfrontiert. In meinem MainViewModel (Singleton-Instanz) habe ich meine statische CreateInstance () -Methode erhalten, die den Dispatcher übernimmt. Und die create-Instanz wird aus der Ansicht aufgerufen, damit ich den Dispatcher von dort aus übergeben kann. Das ViewModel-Testmodul ruft CreateInstance () parameterlos auf.
In einem komplexen Multithread-Szenario ist es jedoch immer gut, eine Schnittstellenimplementierung auf der Ansichtsseite zu haben, um den richtigen Dispatcher für das aktuelle Fenster zu erhalten.
quelle
Vielleicht komme ich etwas spät zu dieser Diskussion, aber ich habe 1 schönen Artikel gefunden: https://msdn.microsoft.com/en-us/magazine/dn605875.aspx
Es gibt 1 Absatz
Angenommen, Sie können async / await ordnungsgemäß verwenden, ist dies kein Problem.
quelle