Wie werden, um thread-sichere Verwendung von INotifyPropertyChanged mit keine SynchronizationContext?
Wie halten Sie Ihre Objekte thread-sicher, dass die INotifyPropertyChanged implementieren? Ich kann nicht mit einem SynchronizationContext, weil ich muss in der Lage sein zu serialisieren des Objekts.
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
//What can I add here to make it thread-safe?
handler(this, new PropertyChangedEventArgs(propertyName));
}
- "Ich kann nicht mit einem SynchronizationContext, weil ich muss in der Lage sein zu serialisieren des Objekts." -- das sollte nicht das problem sein. Haben Sie markiert den Bereich mit
[NonSerialized]
und fügte hinzu, eineOnDeserializing
Methode, um es zurückzusetzen, wenn Sie zu Deserialisieren? - Habe ich nicht. Gibt es eine "einfachere" Weg, als dass Sie gehen, um in meinem code, Versand in die SynchronizationContext-wenn das Objekt erstellt wird? Oder bin ich einfach nur zu faul 😀
- Wenn Sie das Objekt im gleichen Kontext, in dem Sie wünschen, dass der event-Handler ausgeführt werden, können Sie das Feld
SynchronizationContext.Current
im Objekt-Konstruktor, aber sonst, ich bin mir nicht sicher, was der beste Weg zu gehen sein. - Im Allgemeinen würde ich erwarten, dass die Veranstaltung raiser nur die Garantie bieten, dass der thread, auf dem die Eigenschaft geändert wird, ist die eine, die
PropertyChanged
- Ereignis ausgelöst wird, auf (das ist, was dein Beispiel zeigt). Daher würde ich erwarten, dass der handler (vermutlich dein UI oder UI-binding, oder ein UI binding source) zu befassen sich mit der Synchronisation, wenn es wirklich nötig ist. Alternativ, wirklich vorsichtig sein, nur änderungen aus den richtigen thread.
Du musst angemeldet sein, um einen Kommentar abzugeben.
So... stellt sich heraus, dass es eigentlich ein sehr schöner Weg, wenn Sie nichts dagegen haben sich auf eine Verlängerung Generierung von code für Sie zur compile-Zeit. Ich war mit Fody/PropertyChanged sowieso, so dass dies eine sehr einfach ändern. Dies verhindert, dass ein Verweis auf eine
SynchronizationContext
in Modellen, die haben wirklich keine business-wissen über die Benutzeroberfläche.Installieren Sie zuerst PropertyChanged.Fody, erhältlich von NuGet.
Jede Klasse, die derzeit implementiert
INofityPropertyChanged
sollte stattdessen das Attribut[ImplementPropertyChanged]
. Die manuelle Umsetzung sollte entfernt werden. Finden Sie die readme und wiki für weitere Informationen.Einen PropertyChangedNotificationInterceptor muss umgesetzt werden. Sie bieten ein Beispiel für WPF in der wiki; meine Umsetzung für ein WinForms-Projekt:
Set
PropertyChangedNotificationInterceptor.UIContext
irgendwo. Sie könnenPropertyChangedNotificationInterceptor.UIContext = WindowsFormsSynchronizationContext.Current;
im Konstruktor des Hauptformulars.Den
Form
constructor geht durch die Kontrolle Konstruktor und schließlich die Schaffung derWindowsFormsSynchronizationContext
wenn man nicht bereits vorhanden ist. Daher ist es sicher zu erfassen, die.Current
hier. (Hinweis: dies könnte eine Implementierung detail, und könnte sich in Zukunft ändern .NET-Versionen, verschiedene Plattformen, etc.)Beachten Sie, dass dies nur funktioniert, wenn Sie nur einen einzigen sync-Rahmen (einen einzelnen UI-thread). Wenn Sie jemals in das Durcheinander von mehreren UI-threads, und benötigen data-binding auf mehr als einer, wäre dies weitaus komplizierter. Also bitte tun Sie das nicht.
Dank Simon Cropp für das schreiben
PropertyChanged
und auch hilft mir bei der Suche nach dieser bestimmten Eigenschaft.Wenn Sie nicht das Glück und haben die Verwendung von Winforms versuchen Sie es mit MainForm Ihrer Anwendung zum aufrufen von handler im UI thread. Das schlimme ist, dass Sie enthalten
using System.Windows.Forms;
Wenn Sie mit WPF können Sie Marschall Ihre Anrufe an den UI-thread mit dem Dispatcher.
Ich weiß, dass diese Frage bereits beantwortet wurde. Allerdings stolperte ich über das gleiche problem vor einiger Zeit.
Mein Erster Ansatz war sehr die gleichen, als die Antwort von Dan Busha und andere: Zum aufrufen des PropertyChanged-Ereignis auf der gui-Synchronisation Kontext.
Aber meiner Meinung nach ist dies nicht die beste Lösung, weil Sie Ihr Modell kennen muss, um die GUI-bezogene Sachen.
Und es wäre besser, dass die Bindung selbst ist die Synchronisierung mit den GUI-thread.
In Windows Forms gibt es die BindingSource. Um es einfach zu erstellen DataBindings im Designer und andere verbindliche related stuff.
Meine Idee war, mit dem BindingSource, um die Synchronisierung der threads. Im Grunde war meine Idee zum überschreiben aller OnBlaEvent und rufen Sie in den GUI-Thread.
Nur verwenden Sie es wie eine normale Verbindliche Quelle.
Dies ist, was ich kam mit:
InvokeOnUiThread
behandeln sollSynchronizationContext == null
in irgendeiner Weise?