Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
IsEnabled-Binding reagiert nicht auf PropertyChangedEvent
Maendler
myCSharp.de - Member



Dabei seit:
Beiträge: 9
Herkunft: Mürren - Schweiz

Themenstarter:

IsEnabled-Binding reagiert nicht auf PropertyChangedEvent

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
ErfinderDesRades
myCSharp.de - Experte

Avatar #avatar-3151.jpg


Dabei seit:
Beiträge: 5.299

beantworten | zitieren | melden

vielleicht stimmt der angegebene propertyName nicht
Der frühe Apfel fängt den Wurm.
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

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)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Deaktiviertes Profil am .
private Nachricht | Beiträge des Benutzers
LaTino
myCSharp.de - Experte

Avatar #avatar-4122.png


Dabei seit:
Beiträge: 3.003
Herkunft: Thüringen

beantworten | zitieren | melden

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)
private Nachricht | Beiträge des Benutzers
Maendler
myCSharp.de - Member



Dabei seit:
Beiträge: 9
Herkunft: Mürren - Schweiz

Themenstarter:

beantworten | zitieren | melden

Zitat von LaTino
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
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3.170
Herkunft: Trier -> München

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Maendler
myCSharp.de - Member



Dabei seit:
Beiträge: 9
Herkunft: Mürren - Schweiz

Themenstarter:

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1.040

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von p!lle am .
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3.170
Herkunft: Trier -> München

beantworten | zitieren | melden

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
Zitat von MSDN
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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

Hi Maendler,
Zitat von Maendler
Zitat von LaTino
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:
Zitat
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3.170
Herkunft: Trier -> München

beantworten | zitieren | melden

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.
Zitat
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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MarsStein am .
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
private Nachricht | Beiträge des Benutzers