Übersicht über Abhängigkeitseigenschaften (WPF .NET)

Windows Presentation Foundation (WPF) bietet eine Reihe von Diensten, die zum Erweitern der Funktionalität einer Eigenschaft eines Typs verwendet werden können. Zusammen werden diese Dienste als WPF-Eigenschaftensystem bezeichnet. Eine Eigenschaft, die vom WPF-Eigenschaftssystem unterstützt wird, wird als Abhängigkeitseigenschaft bezeichnet. In dieser Übersicht werden das WPF-Eigenschaftssystem und die Funktionen von Abhängigkeitseigenschaften beschrieben, einschließlich der Verwendung vorhandener Abhängigkeitseigenschaften in XAML und in Code. In dieser Übersicht werden auch spezielle Aspekte von Abhängigkeitseigenschaften wie die Metadaten von Abhängigkeitseigenschaften sowie die Erstellung einer eigenen Abhängigkeitseigenschaft in einer benutzerdefinierten Klasse eingeführt.

Wichtig

Der Desktopleitfaden zu .NET 7 und .NET 6 ist in Bearbeitung.

Voraussetzungen

In diesem Artikel werden grundlegende Kenntnisse des .NET-Typsystems und der objektorientierten Programmierung vorausgesetzt. Um die Beispiele in diesem Artikel nachvollziehen zu können, ist es hilfreich, zudem XAML zu verstehen und zu wissen, wie WPF-Anwendungen geschrieben werden. Weitere Informationen finden Sie unter Tutorial: Erstellen einer neuen WPF-App mit .NET.

Abhängigkeitseigenschaften und CLR-Eigenschaften

WPF-Eigenschaften werden in der Regel als standardmäßige .NET-Eigenschaften verfügbar gemacht. Sie können potenziell mit diesen Eigenschaften auf grundlegende Weise interagieren, ohne zu merken, dass sie als Abhängigkeitseigenschaft implementiert sind. Wenn Sie jedoch mit einigen oder allen Features des WPF-Eigenschaftensystems vertraut sind, hilft Ihnen dies dabei, von diesen Features zu profitieren.

Abhängigkeitseigenschaften dienen der Berechnung des Werts einer Eigenschaft anhand des Werts von anderen Eingaben, z. B.:

  • Systemeigenschaften, z. B. Designs und Benutzereinstellungen
  • Just-In-Time-Mechanismen zur Ermittlung von Eigenschaften, z. B. Datenbindung und Animationen/Storyboards
  • Vorlagen mit mehrfacher Verwendung, z. B. Ressourcen und Stile
  • Werte, die aufgrund von Beziehungen mit anderen Elementen in der Elementstruktur bekannt sind (übergeordnete und untergeordnete Elemente)

Außerdem verfügen Abhängigkeitseigenschaft über Folgendes:

  • Eigenständige Validierung
  • Standardwerte
  • Rückrufe, die Änderungen an anderen Eigenschaften überwachen
  • Ein System, das Eigenschaftswerte basierend auf Laufzeitinformationen erzwingen kann.

Abgeleitete Klassen können einige Merkmale einer vorhandenen Eigenschaft durch Überschreiben von Metadaten von Abhängigkeitseigenschaften ändern, anstatt die tatsächliche Implementierung der vorhandenen Eigenschaften zu überschreiben oder neue Eigenschaften zu erstellen.

Anhand der SDK-Referenz können Sie eine Abhängigkeitseigenschaft identifizieren, wenn diese in einem „Informationen zur Abhängigkeitseigenschaft“-Abschnitt auf der verwalteten Verweisseite für diese Eigenschaft vorhanden ist. Der „Informationen zur Abhängigkeitseigenschaft“-Abschnitt enthält einen Link zum DependencyProperty-Bezeichnerfeld für die jeweilige Abhängigkeitseigenschaft. Außerdem enthält sie die Liste der Metadatenoptionen für diese Eigenschaft, Informationen zu Überschreibungen pro Klasse und weitere Details.

Abhängigkeitseigenschaften unterstützen CLR-Eigenschaften

Abhängigkeitseigenschaften und das WPF-Eigenschaftensystem erweitern die Funktionalität von Eigenschaften durch die Bereitstellung eines Typs, der eine Eigenschaft als eine Alternative zum Standardmuster unterstützt, bei dem eine Eigenschaft mit einem privaten Feld unterstützt wird. Der Name dieses Typs lautet DependencyProperty. Der andere wichtige Typ, der das WPF-Eigenschaftssystem definiert, ist DependencyObject. Er definiert die Basisklasse, die eine Abhängigkeitseigenschaft registrieren und besitzen kann.

Folgende Bezeichnungen sollten Sie kennen:

  • Abhängigkeitseigenschaft: Eine Eigenschaft, die durch eine DependencyProperty unterstützt wird.

  • Abhängigkeitseigenschaftenbezeichner: Eine DependencyProperty-Instanz, die als Rückgabewert beim Registrieren einer Abhängigkeitseigenschaft abgerufen und dann als statischer Member einer Klasse gespeichert wird. Viele der APIs, die mit dem WPF-Eigenschaftssystem interagieren, verwenden den Bezeichner der Abhängigkeitseigenschaft als Parameter.

  • CLR-„Wrapper“: Die get- und set-Implementierungen für die Eigenschaft. Diese Implementierungen enthalten den Bezeichner der Abhängigkeitseigenschaft, indem sie ihn in den GetValue- und SetValue-Aufrufen verwenden. Auf diese Weise unterstützt das WPF-Eigenschaftssystem die Eigenschaft.

Das folgende Beispiel definiert die IsSpinning-Abhängigkeitseigenschaft, um die Beziehung zwischen dem DependencyProperty-Bezeichner zur Eigenschaft, die er unterstützt zu veranschaulichen.

public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register(
    "IsSpinning", typeof(bool),
    typeof(MainWindow)
    );

public bool IsSpinning
{
    get => (bool)GetValue(IsSpinningProperty);
    set => SetValue(IsSpinningProperty, value);
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning", GetType(Boolean), GetType(MainWindow))

Public Property IsSpinning As Boolean
    Get
        Return GetValue(IsSpinningProperty)
    End Get
    Set(value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property

Die Namenskonvention der Eigenschaft und ihres unterstützenden DependencyProperty-Feld ist wichtig. Der Name des Felds ist immer der Name der Eigenschaft, die mit dem Suffix Property endet. Weitere Informationen zu dieser Konvention und die Gründe dafür finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften.

Festlegen von Eigenschaftswerten

Sie können Eigenschaften sowohl im Code als auch in XAML festlegen.

Festlegen von Eigenschaftswerten in XAML

Im folgenden XAML-Beispiel wird die Hintergrundfarbe einer Schaltfläche auf Rot gesetzt. Der Zeichenfolgenwert für das XAML-Attribut wird vom WPF-XAML-Parser in einen WPF-Typ konvertiert. Im generierten Code ist der WPF-Typ eine von SolidColorBrush aus umgewandelte Color.

<Button Content="I am red" Background="Red"/>

XAML unterstützt verschiedene Syntaxformen zum Festlegen von Eigenschaften. Welche Syntax für eine bestimmte Eigenschaft verwendet wird, hängt vom Werttyp ab, den eine Eigenschaft verwendet, sowie von anderen Faktoren wie dem Vorhandensein eines Typkonverters. Weitere Informationen zur XAML-Syntax zum Festlegen von Eigenschaften finden Sie unter XAML in WPF und Ausführliche Erläuterung der XAML-Syntax.

Das folgende XAML-Beispiel zeigt einen anderen Schaltflächenhintergrund, der Eigenschaftenelementsyntax anstelle von Attributsyntax verwendet. Anstatt eine einfache Volltonfarbe festzulegen, legt der XAML-Code die Schaltflächeneigenschaft Background auf ein Bild fest. Ein Element repräsentiert dieses Bild, und ein Attribut des geschachtelten Elements gibt die Quelle des Bilds an.

<Button Content="I have an image background">
    <Button.Background>
        <ImageBrush ImageSource="stripes.jpg"/>
    </Button.Background>
</Button>

Festlegen von Eigenschaften im Code

Das Festlegen von Werten für Abhängigkeitseigenschaften in Code geschieht in der Regel über einen Aufruf der set-Implementierung, die vom CLR-Wrapper verfügbar gemacht wird:

Button myButton = new();
myButton.Width = 200.0;
Dim myButton As New Button With {
    .Width = 200.0
}

Das Abrufen eines Eigenschaftswerts besteht im Grunde aus einem Aufruf der Implementierung des get-Wrappers:

double whatWidth = myButton.Width;
Dim whatWidth As Double = myButton.Width

Sie können die Eigenschaften GetValue und SetValue der System-APIs auch direkt aufrufen. Das direkte Aufrufen der APIs ist für einige Szenarien geeignet, aber in der Regel nicht, wenn Sie vorhandene Eigenschaften verwenden. In der Regel sind Wrapper bequemer und bieten einen besseren Zugriff auf die Eigenschaft für Entwicklertools.

Eigenschaften können auch in XAML festgelegt und später über den Code (über die CodeBehind-Datei) darauf zugegriffen werden. Weitere Informationen finden Sie unter CodeBehind und XAML in WPF.

Von einer Abhängigkeitseigenschaft bereitgestellte Eigenschaftenfunktionalität

Im Gegensatz zu einer Eigenschaft, die von einem Feld unterstützt wird, erweitert eine Abhängigkeitseigenschaft die Funktionalität einer Eigenschaft. Häufig repräsentiert oder unterstützt die hinzugefügte Funktionalität eine der folgenden Features:

Ressourcen

Sie können einen Wert einer Abhängigkeitseigenschaft durch Verweisen auf eine Ressource festlegen. Ressourcen werden in der Regel als der Resources-Eigenschaftswert eines Seitenstammelements oder der Anwendung angegeben, da diese Positionen einen einfachen Zugriff auf die Ressource bieten. In diesem Beispiel definieren wir eine SolidColorBrush-Ressource:

<StackPanel.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</StackPanel.Resources>

Nachdem die Ressource definiert ist, können wir auf die Ressource verweisen, um einen Wert für die Background-Eigenschaft bereitzustellen:

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

In WPF-XAML können Sie entweder einen statischen oder dynamischen Ressourcenverweis verwenden. Auf diese bestimmte Ressource wird als DynamicResource verwiesen. Ein dynamischer Ressourcenverweis kann nur verwendet werden, um eine Abhängigkeitseigenschaft festzulegen. Daher wird vom WPF-Eigenschaftensystem insbesondere die Verwendung dynamischer Ressourcenverweise ermöglicht. Weitere Informationen finden Sie unter XAML-Ressourcen.

Hinweis

Ressourcen werden als ein lokaler Wert behandelt. Wenn Sie also einen anderen lokalen Wert festgelegt haben, beseitigen Sie den Verweis auf die Ressource. Weitere Informationen finden Sie unter Priorität von Abhängigkeitseigenschaftswerten.

Datenbindung

Eine Abhängigkeitseigenschaft kann über die Datenbindung auf einen Wert verweisen. Die Datenbindung funktioniert über eine bestimmte Markuperweiterungssyntax in XAML oder das Binding-Objekt im Code. Mit der Datenbindung wird die Bestimmung des letztendlichen Eigenschaftswerts bis zur Laufzeit zurückgestellt. Zu diesem Zeitpunkt wird der Wert aus einer Datenquelle abgerufen.

Das folgende Beispiel legt mithilfe einer in XAML deklarierten Bindung die Eigenschaft Content für eine Button-Klasse fest. Die Bindung verwendet einen geerbten Datenkontext sowie eine XmlDataProvider-Datenquelle (hier nicht gezeigt). Die Bindung selbst gibt die Quelleigenschaft anhand eines XPath innerhalb der Datenquelle an.

<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>

Hinweis

Bindungen werden als ein lokaler Wert behandelt. Wenn Sie also einen anderen lokalen Wert festlegen, beseitigen Sie die Bindung. Weitere Informationen finden Sie unter Priorität von Abhängigkeitseigenschaftswerten.

Die Abhängigkeitseigenschaften (oder die DependencyObject-Klasse) unterstützen INotifyPropertyChanged nicht nativ für Benachrichtigungen über Änderungen im Wert DependencyObject für die Quelleigenschaft für Datenbindungsvorgänge. Weiteres zum Erstellen von Eigenschaften für die Datenbindung, die Änderungen an einem Datenbindungsziel melden können, finden Sie unter Übersicht über die Datenbindung.

Stile

Stile und Vorlagen sind überzeugende Gründe für die Verwendung von Abhängigkeitseigenschaften. Stile eignen sich insbesondere für das Festlegen von Eigenschaften, die die Benutzeroberfläche der Anwendung definieren. Stile werden in XAML in der Regel als Ressourcen definiert. Stile interagieren mit dem Eigenschaftensystem, weil sie normalerweise „Setter“ für bestimmte Eigenschaften und „Trigger“ enthalten, die einen Eigenschaftswert basierend auf dem Echtzeitwert einer anderen Eigenschaft ändern.

Im folgenden Beispiel wird ein einfacher Stil erstellt, der in einem Resources-Wörterbuch (nicht gezeigt) definiert wird. Anschließend wird dieser Stil direkt auf die Style-Eigenschaft für einen Button angewendet. Der Setter innerhalb des Stils legt die Eigenschaft Background für eine formatierte Button auf „green“ (grün) fest.

<Style x:Key="GreenButtonStyle">
    <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}" Content="I am green"/>

Weitere Informationen finden Sie unter Erstellen von Formaten und Vorlagen.

Animationen

Abhängigkeitseigenschaften können animiert werden. Wenn eine angewendete Animation ausgeführt wird, hat der animierte Wert höhere Priorität als jeder andere Eigenschaftswert, einschließlich eines lokalen Werts.

Im folgenden Beispiel wird die Background-Eigenschaft eines Button festgelegt. Technisch gesehen legt die Syntax des Eigenschaftselements einen leeren SolidColorBrush als Background fest, und die Color-Eigenschaft des SolidColorBrush wird animiert.

<Button Content="I am animated">
    <Button.Background>
        <SolidColorBrush x:Name="AnimBrush"/>
    </Button.Background>
    <Button.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <ColorAnimation
                        Storyboard.TargetName="AnimBrush" 
                        Storyboard.TargetProperty="(SolidColorBrush.Color)"
                        From="Blue" To="White" Duration="0:0:1" 
                        AutoReverse="True" RepeatBehavior="Forever" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>

Weiteres zum Animieren von Eigenschaften finden Sie unter Übersicht über Animationen und Übersicht über Storyboards.

Überschreiben von Metadaten

Sie können bestimmte Verhaltensweisen einer Abhängigkeitseigenschaft ändern, indem Sie ihre Metadaten überschreiben, wenn Sie von der Klasse ableiten, die die Abhängigkeitseigenschaft ursprünglich registrierte. Das Überschreiben von Metadaten basiert auf dem DependencyProperty-Bezeichner und erfordert kein erneutes Implementieren der Eigenschaft. Die Metadatenänderung wird nativ vom Eigenschaftssystem gehandhabt. Jede Klasse enthält möglicherweise individuelle Metadaten für alle Eigenschaften, die je nach Typ von Basisklassen geerbt wurden.

Das folgende Beispiel überschreibt Metadaten für eine DefaultStyleKey-Abhängigkeitseigenschaft. Das Überschreiben der Metadaten dieser Abhängigkeitseigenschaft ist Teil eines Implementierungsmusters zum Erstellen von Steuerelementen, die Standardstile aus Designs verwenden können.

public class SpinnerControl : ItemsControl
{
    static SpinnerControl() => DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl),
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
}
Public Class SpinnerControl
    Inherits ItemsControl
    Shared Sub New()
        DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
    End Sub
End Class

Weitere Informationen zum Überschreiben oder Zugreifen auf Metadaten für Abhängigkeitseigenschaften finden Sie unter Überschreiben von Metadaten für eine Abhängigkeitseigenschaft.

Vererbung von Eigenschaftswerten

Ein Element kann den Wert einer Abhängigkeitseigenschaft von seinem übergeordneten Element in der Objektstruktur erben.

Hinweis

Das Vererbungsverhalten für Eigenschaftswerte ist nicht global für alle Abhängigkeitseigenschaften aktiviert, da die Berechnungszeit für die Vererbung die Leistung beeinträchtigt. Die Eigenschaftswertvererbung ist normalerweise nur aktiviert, wenn sie sinnvoll anwendbar ist. Im Abschnitt Informationen zur Abhängigkeitseigenschaft zu der Abhängigkeitseigenschaft in der SDK-Referenz können Sie sehen, ob eine Abhängigkeitseigenschaft erbt.

Im folgenden Beispiel wird eine Bindung gezeigt, die die DataContext-Eigenschaft enthält, um die Quelle der Bindung anzugeben. Bindungen in untergeordneten Objekt müssen die Quelle also nicht angeben und können den geerbten Wert von DataContext im übergeordneten StackPanel-Objekt verwenden. Ein untergeordnetes Objekt kann auch direkt seinen eigenen DataContext oder eine Source im Binding angeben und nicht den geerbten Wert verwenden.

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource TestData}}">
    <Button Content="{Binding XPath=test[2]/@text}"/>
</StackPanel>

Weitere Informationen finden Sie unter Vererbung von Eigenschaftswerten.

WPF-Designer-Integration

Benutzerdefinierte Steuerelemente mit als Abhängigkeitseigenschaften implementierten Eigenschaften integrieren sich gut mit dem WPF-Designer für Visual Studio. Ein Beispiel hierfür ist die Möglichkeit, direkte und angefügte Abhängigkeitseigenschaften mit dem Eigenschaften-Fenster zu bearbeiten. Weitere Informationen finden Sie unter Übersicht über das Erstellen von Steuerelementen.

Priorität von Abhängigkeitseigenschaftswerten

Jede der eigenschaftenbasierten Eingaben im WPF-Eigenschaftssystem kann den Wert einer Abhängigkeitseigenschaft festlegen. Priorisierung von Abhängigkeitseigenschaftswerten geschieht, damit die verschiedenen Szenarien zur Art und Weise, in der Eigenschaften ihre Werte erhalten, vorhersagbar interagieren können.

Hinweis

In der SDK-Dokumentation werden manchmal im Zusammenhang mit Abhängigkeitseigenschaften die Begriffe „lokaler Wert“ oder „lokal festgelegter Wert“ verwendet. Ein lokal festgelegter Wert ist ein Eigenschaftswert, der für eine Objektinstanz direkt im Code oder als Elementattribut in XAML festgelegt wird.

Das nächste Beispiel enthält einen Stil, der für die Background-Eigenschaft aller Schaltflächen gilt, gibt aber eine Schaltfläche mit einer lokal festgelegten Background-Eigenschaft an. Technisch gesehen wurde die Background-Eigenschaft dieser Schaltfläche zweimal festgelegt, doch es gilt nur ein Wert – und zwar derjenige mit der höchsten Priorität. Ein lokal festgelegter Wert hat die höchste Priorität, außer für eine laufende Animation, die hier nicht vorliegt. So verwendet die zweite Schaltfläche den lokal festgelegten Wert für die Background-Eigenschaft anstelle des Setter-Werts für den Stil. Die erste Schaltfläche verfügt über keinen lokalen oder anderen Wert mit höherer Priorität als der eines Stil-Setters und verwendet daher den Wert des Stil-Setters für die Background-Eigenschaft.

<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Orange"/>
        </Style>
    </StackPanel.Resources>
    <Button>I am styled orange</Button>
    <Button Background="Pink">I am locally set to pink (not styled orange)</Button>
</StackPanel>

Warum haben Abhängigkeitseigenschaften Prioritäten?

Lokal festgelegte Werte haben Vorrang vor Werten von Stil-Settern, was die lokale Steuerung von Elementeigenschaften unterstützt. Weitere Informationen finden Sie unter Priorität von Abhängigkeitseigenschaftswerten.

Hinweis

Eine Reihe von Eigenschaften, die für WPF-Elemente definiert sind, sind keine Abhängigkeitseigenschaften, da Abhängigkeitseigenschaften in der Regel nur implementiert wurden, wenn ein Feature des WPF-Eigenschaftssystems erforderlich war. Die Features umfassen Datenbindung, Formatierung, Animation, Unterstützung für Standardwerte, Vererbung, angefügte Eigenschaften und Invalidierung.

Wissenswertes zu Abhängigkeitseigenschaften

  • Komponenten- oder Anwendungsentwickler können ihre eigene Abhängigkeitseigenschaft erstellen, um Funktionen wie die Datenbindung oder die Unterstützung von Stilen oder die Invalidierung und die Erzwingung von Werten hinzuzufügen. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften.

  • Betrachten Sie Abhängigkeitseigenschaften als öffentliche Eigenschaften, die für jeden Aufrufer mit Zugriff auf eine Instanz zugänglich oder erkennbar sind. Weitere Informationen finden Sie unter Sicherheit von Abhängigkeitseigenschaften.

  • Eine angefügte Eigenschaft ist ein Eigenschaftstyp, die eine spezielle Syntax in XAML unterstützt. Eine angefügte Eigenschaft verfügt oft über keine 1:1-Entsprechung mit einer Common Language Runtime-Eigenschaft und ist nicht unbedingt eine Abhängigkeitseigenschaft. Der Hauptzweck einer angehängten Eigenschaft besteht darin, untergeordneten Elementen die Möglichkeit zu geben, Eigenschaftswerte an ein übergeordnetes Element zu melden, auch wenn das übergeordnete Element und das untergeordnete Element nicht diese Eigenschaft als Teil der Klassenmemberlisten enthalten. Ein primäres Szenario besteht darin, es einem untergeordneten Element zu ermöglichen, übergeordnete Elemente darüber zu informieren, wie sie in der Benutzeroberfläche dargestellt werden sollen. Beispiele zu diesem Thema finden Sie unter Dock und Left. Weitere Informationen finden Sie unter Übersicht über angefügte Eigenschaften.

Weitere Informationen