Dependency Properties, endlich verstanden
- Matt
Dependency Properties sind der Teil von WPF, den man zehn Jahre lang benutzt, ohne ihn erklären zu können. Der Code dafür ist Formelkram, den man aus einem Codeschnipsel einfügt:
public static readonly DependencyProperty TitelProperty =
DependencyProperty.Register(
nameof(Titel), typeof(string), typeof(MeinControl),
new PropertyMetadata(string.Empty, AufTitelGeaendert));
public string Titel
{
get => (string)GetValue(TitelProperty);
set => SetValue(TitelProperty, value);
}
Warum das nicht einfach public string Titel { get; set; } sein darf, hat drei Gründe.
Speicher
Ein Button hat über hundert Eigenschaften. Als Felder wären das über hundert Speicherplätze pro Instanz, auch wenn nur zwei davon vom Standard abweichen. Dependency Properties speichern nur die abweichenden Werte, alles andere kommt aus den Metadaten des Typs.
Bei einer Liste mit tausend Einträgen ist das kein Detail mehr.
Vererbung und Vorrang
Setzt man FontSize auf einem Fenster, gilt sie für alles darin. Das geht nur, weil der Wert nicht im Element steht, sondern beim Lesen ermittelt wird: erst lokaler Wert, dann Animation, dann Trigger, dann Stil, dann Vererbung, dann Standard.
Genau diese Reihenfolge ist der Grund, warum ein Wert, den man im Code setzt, von einem Trigger nicht mehr überschrieben wird. Ein lokal gesetzter Wert steht weit oben. Das ist die häufigste Verwirrung mit WPF überhaupt, und sie löst sich auf, sobald man die Rangfolge kennt.
Benachrichtigung ohne INotifyPropertyChanged
Bindungen, Trigger und Animationen brauchen eine Meldung, wenn sich etwas ändert. Bei Dependency Properties ist das eingebaut, bei normalen Eigenschaften muss man es selbst bauen.
Wann man eine eigene braucht
Selten. Faustregel: nur an Steuerelementen, nie an ViewModels. Ein ViewModel benutzt INotifyPropertyChanged, wofür das CommunityToolkit den Code erzeugt.
Eine eigene Dependency Property braucht man, wenn ein selbstgebautes Steuerelement etwas anbieten soll, worauf im XAML gebunden, gestylt oder animiert wird. Und für Attached Properties, also die Variante, die Werte an fremde Elemente hängt, wie es Behaviors tun.
Für alles andere reicht eine normale Eigenschaft, und das ist die Erkenntnis, die mir jahrelang gefehlt hat.