Laden...

IsEnabled-Binding reagiert nicht auf PropertyChangedEvent

Erstellt von Maendler vor 7 Jahren Letzter Beitrag vor 7 Jahren 2.945 Views
M
Maendler Themenstarter:in
9 Beiträge seit 2011
vor 7 Jahren
IsEnabled-Binding reagiert nicht auf PropertyChangedEvent

Hallo zusammen,

Ich habe eine Combobox, die je nach Auswahl einer andern Combobox disabled oder enabled sein soll.



<DatePicker Grid.Row="3" Grid.Column="1" SelectedDate="{Binding RangeEndTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                      IsEnabled="{Binding IsEventDurationEnabled, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold" HorizontalAlignment="Left" 
                        VerticalAlignment="Center" Width="100" Margin="2.5"/>


Da sonst alle PropertyChangedEvents abgeholt werden, stehe ich völig auf dem Schlauch.

Der Code des PropertyChangedEvents ist;



private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(typeof(T), new PropertyChangedEventArgs(propertyName));
        }


Blickt da jemand durch?

Gruss Alex

5.299 Beiträge seit 2008
vor 7 Jahren

vielleicht stimmt der angegebene propertyName nicht

Der frühe Apfel fängt den Wurm.

D
985 Beiträge seit 2014
vor 7 Jahren

Ich invoke so einen Event immer mit this (also der Referenz von der Instanz die den Event auslöst) und nicht mit dem Type von (ähh, ja von welchem überhaupt).

PS So eine Event-Raiser Methode sollte immer als protected virtual deklariert werden. Erleichtert oft das Leben ;o)

3.003 Beiträge seit 2006
vor 7 Jahren

Wieso invokest du mit einem Typ als sender?

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

M
Maendler Themenstarter:in
9 Beiträge seit 2011
vor 7 Jahren

Wieso invokest du mit einem Typ als sender?

Der void ist eigntlich protected und befindet sich in einer generischen Basisklasse für alle Views, der ich ten Typ der abgeleiteten Klasse mitgebe.

Gruss Alex

3.170 Beiträge seit 2006
vor 7 Jahren

Hallo,

also mit dem Typen kann es nicht funktionieren. Du brauchst auf jeden Fall das konkrete Objekt als sender.
Stell Dir einfach mal vor, Du hast mehrere Deiner VM-Objekte in verschiedenen Views, eines davon ändert sich, das andere nicht. Wie soll denn über den Typen entschieden werden, welche View dann aktualisiert werden soll?

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

M
Maendler Themenstarter:in
9 Beiträge seit 2011
vor 7 Jahren

Hallo MarsStein,

Ich denke nicht, dass die übergabe mit typeof(T) den Fehler verursacht, da sont auch alle PropertyChangedEvents nicht abgehohlt würden. Dies ist jedoch der in allen Datenrelevanten Properties der fall, also muss meines erachtens dies keine Rolle spielen.

Gruss Alex

1.040 Beiträge seit 2007
vor 7 Jahren

Dann binde doch einfach mal an eine Property, bei der es geht (ggf. mit Converter zwischen) - um sicherzustellen, ob da überhaupt was ankommt bzw. das IsEnabled funktioniert.

Und schaue in das Output, ob du Binding-Fehler hast.

Und zeige mal deine Property IsEventDurationEnabled.

3.170 Beiträge seit 2006
vor 7 Jahren

Hallo,

möglicherweise funktionieren Deine Properties auch mit dem Typen. Da würde ich mich aber jedenfalls nicht drauf verlassen - Gründe stehen oben.
Das Event wird ja von Framework-Klassen konsumiert, und nicht von Dir selbst. Da könnte es dann fallweise implementierungsabhängig sein, ob und wie die Events konsumiert werden.

Früher stand das als Konvention explizit in der Doku:
Raising an Event

By convention, events in the .NET Framework have the signature EventName(sender, e), where sender is an Object that provides a reference to the class or structure that fired the event

Der Artikel wurde allerdings überarbeitert, und diese Konvention ist nicht mehr explizit genannt.

Andere Sache, von der ich aber nicht glaube, dass sie Dein Problem auslöst:
Mode=OneWay und UpdateSourceTrigger passen nicht wirklich zusammen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

5.658 Beiträge seit 2006
vor 7 Jahren

Hi Maendler,

Wieso invokest du mit einem Typ als sender?

Der void ist eigntlich protected und befindet sich in einer generischen Basisklasse für alle Views, der ich ten Typ der abgeleiteten Klasse mitgebe.

Das klingt aber sehr abenteuerlich... Eine Basisklasse, die den Typ der konkreten Implementierung als Typ-Parameter übergeben bekommt? Wozu soll das gut sein?

Und unabhängig davon sollte es trotzdem heißen:

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

Weeks of programming can save you hours of planning

3.170 Beiträge seit 2006
vor 7 Jahren

Hallo,

ich habe mir jetzt mal angesehen, was da eigentlich im Hintergrund passiert:

WPF benutzt den PropertyChangedEventManager, einen spezialisierten WeakEventManager, um auf die PropertyChanged Events des VM zu reagieren.
Ich beziehe mich im Folgenden auf die Codezeilen aus der verlinkten Quelle.

Irgendwann wird die AddListener-Methode (276) aufgerufen, diese ordnet dem _Quellobjekt _(dem VM oder genauer: dem Source-Objekt des Bindings) ein Dictionary zu (287), in dem zum gewünschten Propertynamen - der ja über das Binding bekannt ist - eine Liste mit den benötigten Handlern gehalten wird.

Anschließend wird in (290) die Methode StartListening (150) aufgerufen, welche das PropertyChanged-Event abonniert.

Der registrierte Handler findet sich ab (378). Dort wird zunächst versucht, das dem _Quellobjekt _(diesmal sender) zugeordnete Dictionary zu finden (387). Wird es nicht gefunden, wird eine leere Handlerliste benutzt (389-394), und damit bist Du aus der Nummer raus.

Genau das ist hier der Fall: Da der sender der _Typ _und nicht das Quellobjekt ist, existiert auch kein Dictionary dazu, und es passiert nichts mehr weiter.

WPF bzw. der PropertyChangedEventManager geht also sehr wohl davon aus, dass das Objekt als sender übergeben wird, das die geänderte Property enthält. An einem kleinen einfachen Beispiel konnte ich das auch genau so nachvollziehen.

da sont auch alle PropertyChangedEvents nicht abgehohlt würden. Dies ist jedoch der in allen Datenrelevanten Properties der fall, also muss meines erachtens dies keine Rolle spielen.

Der oben gezeigte Mechanismus - sofern ich ihn richtig verstanden habe - verleitet mich dazu, das Gegenteil zu behaupten.
Das kann eigentlich nur funktionieren, wenn da ganze DataContext-Objekte ausgetauscht werden, oder ObservableCollections geändert werden, dann läuft das ganze wieder etwas anders. Die Gegenrichtung - Updaten des ViewModels aus der View - ist natürlich auch nicht betroffen.

Ich glaube, dass Du da einem Trugschluss aufgesessen bist. Die Bindings funktioneren zwar initial, Änderungsbenachrichtigungen direkt vom ViewModel über INPC kann die View aber auf diese Weise nicht erhalten.

Also tu Dir selbst den Gefallen und probier es einfach einmal aus, statt Dich auf Dein seltsames Konzept zu vesteifen - das funktioniert nämlich schlichtweg nicht.

Gruß, MarsStein

Edit: Typos

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca