So ... stellt sich heraus, es ist eigentlich eine sehr schöne Art und Weise schließen, wenn Sie nicht auf einer Verlängerung unter Berufung nichts dagegen einige Code für Sie bei der Kompilierung zu erzeugen Zeit. Ich habe sowieso Fody/PropertyChanged benutzt, was dies sehr leicht macht. Dies vermeidet, einen Verweis auf eine SynchronizationContext
in Modellen zu haben, die wirklich kein Business über die Benutzeroberfläche wissen.
Zuerst installieren PropertyChanged.Fody, von NuGet zur Verfügung.
Jede Klasse, die derzeit INofityPropertyChanged
implementiert, sollte stattdessen das Attribut [ImplementPropertyChanged]
haben. Die manuelle Implementierung sollte entfernt werden. Weitere Informationen finden Sie in den Artikeln readme und wiki.
Ein PropertyChangedNotificationInterceptor muss implementiert werden. Sie stellen ein Beispiel für WPF im Wiki dar; meine Implementierung für ein WinForms Projekt:
public static class PropertyChangedNotificationInterceptor
{
public static SynchronizationContext UIContext { get; set; }
public static void Intercept(object target, Action onPropertyChangedAction, string propertyName)
{
if (UIContext != null)
{
UIContext.Post(_ =>
{
onPropertyChangedAction();
}, null);
}
else
{
onPropertyChangedAction();
}
}
}
Set PropertyChangedNotificationInterceptor.UIContext
irgendwo. Sie können PropertyChangedNotificationInterceptor.UIContext = WindowsFormsSynchronizationContext.Current;
in den Konstruktor Ihres Hauptformulars einfügen.
Die Form
constructor geht durch die Control constructor und wird schließlich am Ende WindowsFormsSynchronizationContext
erstellen, wenn es noch nicht existiert. Daher ist es sicher, die .Current
hier zu erfassen. (Anmerkung: Dies könnte eine Implementierung Detail sein, und in Zukunft .NET-Versionen, verschiedene Plattformen verändern könnte, usw.)
Beachten Sie, dass dies nur funktioniert, wenn Sie nur einen einzigen Sync-Kontext haben (ein einzelnes UI-Thread). Wenn Sie jemals in die Unordnung mehrerer UI-Threads geraten, und erfordern Datenbindung auf mehr als einer, würde dies viel komplizierter werden. Also bitte tu das nicht.
Dank Simon Cropp zum Schreiben PropertyChanged
und hilft mir auch, diese besondere Funktion zu finden.
"Ich kann keinen SynchronizationContext verwenden, weil ich das Objekt serialisieren muss." - Das sollte kein Problem sein. Haben Sie das Feld mit '[NonSerialized]' markiert und eine 'OnDeserializing' Methode hinzugefügt, um es beim Deserialisieren zurückzusetzen? – hvd
Ich habe nicht. Gibt es einen "einfacheren" Weg, als in meinem Code herumzugehen und den SynchronizationContext zu senden, wenn das Objekt erstellt wird?Oder bin ich einfach zu faul: D – Stephen
Wenn Sie das Objekt in demselben Kontext erstellen, in dem die Ereignisbehandlungsroutinen ausgeführt werden sollen, können Sie das Feld im Konstruktor des Objekts auf "SynchronizationContext.Current" setzen. Ich bin mir nicht sicher, was der beste Weg wäre zu gehen. – hvd