Übersicht über Abhängigkeitseigenschaften

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 normalerweise als WPF-Eigenschaftensystem bezeichnet. Eine Eigenschaft, die von der WPF-Eigenschaft unterstützt wird, wird als Abhängigkeitseigenschaft bezeichnet. In dieser Übersicht wird das WPF-Eigenschaftensystem und die Funktionen einer Abhängigkeitseigenschaft beschrieben. Dies schließt die Verwendung vorhandener Abhängigkeitseigenschaften in XAML und Code ein. 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.

Voraussetzungen

In diesem Thema wird vorausgesetzt, dass Sie über einige grundlegende Kenntnisse zum Typsystem von .NET und die objektorientierte Programmierung verfügen. Um den Beispielen in diesem Thema zu folgen, sollten Sie zudem XAML verstehen und wissen, wie WPF-Anwendungen geschrieben werden. Weitere Informationen finden Sie unter Exemplarische Vorgehensweise: Meine erste WPF-Desktopanwendung.

Abhängigkeitseigenschaften und CLR-Eigenschaften

Eigenschaften werden in der Regel als .NET-Standardeigenschaften verfügbar gemacht. Grundsätzlich können Sie direkt mit diesen Eigenschaften direkt interagieren, ohne zu wissen, dass sie als Abhängigkeitseigenschaft implementiert werden. Sie sollten aber mit einigen oder allen Funktionen des WPF-Eigenschaftensystems vertraut sein, damit Sie sie nutzen können.

Abhängigkeitseigenschaften dienen der Berechnung des Werts einer Eigenschaft anhand des Werts von anderen Eingaben. Zu diese anderen Eingaben gehören Systemeigenschaften wie Designs und die Benutzervoreinstellung, Feststellungsmechanismen für Just-In-Time-Eigenschaft wie die Datenbindung und Animationen/Storyboards, mehrfach verwendbare Vorlagen, z.B. Ressourcen und Stile, oder Werte, die über übergeordnete und untergeordnete Beziehungen mit anderen Elementen in der Elementstruktur bekannt sind. Darüber hinaus kann eine Abhängigkeitseigenschaft implementiert werden, um ein selbstständige Überprüfung, Standardwerte, Rückrufe, die Änderungen an anderen Eigenschaften überwachen, sowie ein System bereitzustellen, das Eigenschaftswerte auf Grundlage potenzieller Laufzeitinformationen erzwingen kann. Abgeleitete Klassen können auch einige spezifische Merkmale einer vorhandenen Eigenschaft durch Überschreiben von Metadaten für 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 ermitteln, welche Eigenschaft eine Abhängigkeitseigenschaft ist, wenn diese im Abschnitt „Informationen zur Abhängigkeitseigenschaft“ auf der verwalteten Referenzseite für diese Eigenschaft vorhanden ist. Der Abschnitt mit den Informationen zur Abhängigkeitseigenschaft enthält einen Link zum DependencyProperty-Bezeichner für diese Abhängigkeitseigenschaft und eine Liste der Metadatenoptionen für diese Eigenschaft, der Informationen für das Überschreiben pro Klasse und anderer 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 Implementierung zum Standardmuster unterstützt, bei dem die Eigenschaft mit einem privaten Feld unterstützt wird. Der Name dieses Typs lautet DependencyProperty. Der andere wichtige Typ, der das WPF-Eigenschaftensystem definiert, ist DependencyObject. DependencyObject definiert die Basisklasse, die eine Abhängigkeitseigenschaft registrieren und besitzen kann.

Nachfolgend ist die Terminologie aufgeführt, die mit Abhängigkeitseigenschaften verwendet wird:

  • Abhängigkeitseigenschaft: Eine Eigenschaft, die von einer DependencyProperty-Klasse gesichert 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. Dieser Bezeichner wird als Parameter für viele der APIs verwendet, die mit dem WPF-Eigenschaftenssystem interagieren.

  • CLR-Wrapper: Die tatsächlichen Implementierungen zum Abrufen und Festlegen für die Eigenschaft. Diese Implementierungen beinhalten den Abhängigkeitseigenschaftenbezeichner, indem sie diesen in den Aufrufen GetValue und SetValue verwenden und so die Sicherung für die Eigenschaft über das WPF-Eigenschaftensystem bereitstellen.

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

public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning",
                                GetType(Boolean),
                                GetType(MyCode))

Public Property IsSpinning() As Boolean
    Get
        Return CBool(GetValue(IsSpinningProperty))
    End Get
    Set(ByVal 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 folgende XAML-Beispiel wird die Hintergrundfarbe einer Schaltfläche als Rot dargestellt. Dieses Beispiel zeigt einen Fall, in dem der einfache Zeichenfolgenwert für ein XAML-Attribut vom WPF XAML-Parser im generierten Code in einen WPF-Typ typkonvertiert wird (ein Color mit einer SolidColorBrush).

<Button Background="Red" Content="Button!"/>

XAML unterstützt eine Vielzahl an 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.

Im folgende XAML-Beispiel wird ein Beispiel für eine Syntax ohne Attribut und einen anderen Hintergrund für eine Schaltfläche. Diesmal wird nicht einfach eine Volltonfarbe, sondern der Hintergrund auf ein Bild mit einem Element festgelegt, das dieses Bild und die Bildquelle angegeben als Attribut des geschachtelten Elements darstellt. Dies ist ein Beispiel für Eigenschaftenelementsyntax.

<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

Festlegen von Eigenschaften im Code

Das Festlegen von Abhängigkeitseigenschaften im Code geschieht in der Regel über einen Aufruf der festgelegten Implementierung, die vom CLR-Wrapper verfügbar gemacht wird.

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

Das Abrufen eines Eigenschaftswerts besteht auch im Grunde aus einem Aufruf der Implementierung zum Abrufen des Wrappers:

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

Sie können die Eigenschaften GetValue und SetValue der System-APIs auch direkt aufrufen. Dies ist üblicherweise nicht erforderlich, wenn Sie vorhandene Eigenschaften verwenden (die Wrapper sind besser geeignet und stellen eine bessere Verfügbarkeit der Eigenschaft für Entwicklungswerkzeuge bereit). Das Aufrufen der APIs ist jedoch geeignet für bestimmte Szenarios.

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 Code-Behind und XAML in WPF.

Von einer Abhängigkeitseigenschaft bereitgestellte Eigenschaftenfunktionalität

Eine Abhängigkeitseigenschaft stellt Funktionen bereit, die die Funktionalität einer Eigenschaft gegenüber einer Eigenschaft übertreffen, die durch ein Feld unterstützt wird. Oft stellt eine solche Funktion eine der folgenden spezifischen Features dar bzw. unterstützt es:

Ressourcen

Ein Wert einer Abhängigkeitseigenschaft kann durch Verweisen auf eine Ressource festgelegt werden. Ressourcen werden in der Regel als der Resources-Eigenschaftswert eines Seitenstammelements oder der Anwendung angegeben (diese Positionen ermöglichen den einfachsten Zugriff auf die Ressource). Das folgende Beispiel veranschaulicht, wie Sie eine SolidColorBrush-Ressource definieren.

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

Nachdem die Ressource definiert wurde, können Sie auf die Ressource verweisen und einen Eigenschaftswert bereitstellen:

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

Auf diese spezielle Ressource wird als ein DynamicResource-Markuperweiterung verwiesen (in WPF-XAML können Sie entweder einen statischen oder dynamischen Ressourcenverweis verwenden). Um einen dynamischen Ressourcenverweis zu verwenden, müssen Sie die Ressource auf eine Abhängigkeitseigenschaft festlegen. 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 letzte Bestimmung des 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 gewünschte Quelleigenschaft mithilfe von XPath innerhalb der Datenquelle an.

<Button Content="{Binding XPath=Team/@TeamName}"/>

Hinweis

Bindungen werden als ein lokaler Wert behandelt. Wenn Sie also einen anderen lokalen Wert festgelegt haben, 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 zu Zwecken der Erstellung von Benachrichtigungen von Änderungen im Wert DependencyObject für die Quelleigenschaft für Datenbindungsvorgänge. Weitere Informationen 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 zwei Hauptgründe für die Verwendung von Abhängigkeitseigenschaften. Stile eignen sich besonders 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 sowohl „Setter“ für bestimmte Eigenschaften als auch „Trigger“ enthalten, die einen Eigenschaftswert basierend auf dem Echtzeitwert einer anderen Eigenschaft ändern.

Im folgenden Beispiel wird ein recht einfacher Stil erstellt, der in einem Resources-Wörterbuch definiert wird (hier nicht gezeigt). Dieser Stil wird direkt auf die Style-Eigenschaft für eine 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}">I am green!</Button>

Weitere Informationen finden Sie unter Erstellen von Formaten und Vorlagen.

Animationen

Abhängigkeitseigenschaften können animiert werden. Wenn eine Animation angewendet wurde und ausgeführt wird, verfügt der animierte Wert über eine höhere Priorität als alle anderen Werte (z.B. ein lokaler Wert), über die die Eigenschaft sonst verfügt.

Im folgenden Beispiel wird die Background-Eigenschaft auf einer Button-Eigenschaft animiert (genau genommen wird Background über die Eigenschaftenelementsyntax animiert, um eine leere SolidColorBrush-Klasse als Background anzugeben. Die Color-Eigenschaft dieser SolidColorBrush ist somit die Eigenschaft, die direkt animiert wird).

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

Weitere Informationen zur Animation 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 die Metadaten für diese Eigenschaft überschreiben, wenn Sie von der Klasse ableiten, die die Abhängigkeitseigenschaft ursprünglich registriert. Das Überschreiben von Metadaten basiert auf dem Bezeichner DependencyProperty. Das Überschreiben von Metadaten erfordert keine erneute Implementierung der Eigenschaft. Die Metadatenänderung wird vom Eigenschaftensystem nativ verarbeitet. Jede Klasse kann potenziell individuelle Metadaten für alle Eigenschaften enthalten, die von den Basisklassen jeweils pro Typ geerbt werden.

Das folgende Beispiel überschreibt Metadaten für eine DefaultStyleKey-Abhängigkeitseigenschaft. Das Überschreiben der Metadaten dieser Abhängigkeitseigenschaft ist Teil eines Implementierungsmusters, das Steuerelemente erstellt, 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 über das Überschreiben oder Abrufen von Eigenschaftenmetadaten finden Sie unter Metadaten für Abhängigkeitseigenschaften.

Vererbung von Eigenschaftswerten

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

Hinweis

Das Vererbungsverhalten von Eigenschaftswerten ist nicht global für alle Abhängigkeitseigenschaften aktiviert, da die Berechnungszeit für die Vererbung Leistungseinbußen mit sich bringt. Die Vererbung von Eigenschaftswerten ist normalerweise nur für Eigenschaften aktiviert, für die die Vererbung von Eigenschaftswerten in einem bestimmten Szenario sinnvoll ist. Anhand des Abschnitts Informationen zur Abhängigkeitseigenschaft zu der Abhängigkeitseigenschaft in der SDK-Referenz können Sie ermitteln, ob eine Abhängigkeitseigenschaft erbt.

Im folgenden Beispiel wird eine Bindung gezeigt und die DataContext-Eigenschaft festgelegt, die die Quelle der Bindung angibt, die im früheren Bindungsbeispiel nicht gezeigt wurde. Alle nachfolgenden Bindungen in untergeordneten Objekt müssen die Quelle nicht angeben. Sie können den geerbten Wert von DataContext im übergeordneten StackPanel-Objekt verwenden. (Alternativ kann ein untergeordnetes Objekt stattdessen direkt seine eigene DataContext-Eigenschaft oder eine Source in der Binding angeben und so bewusst den geerbten Wert für den Datenkontext der Bindungen nicht verwenden.)

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

Weitere Informationen finden Sie unter Vererbung von Eigenschaftswerten.

WPF-Designer-Integration

Ein benutzerdefiniertes Steuerelement mit Eigenschaften, die als Abhängigkeitseigenschaften implementiert werden, erhalten entsprechenden WPF Designer for Visual Studio-Support. Ein Beispiel hierfür ist die Fähigkeit, 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

Wenn Sie den Wert einer Abhängigkeitseigenschaft abrufen, erhalten Sie möglicherweise einen Wert, der mithilfe einer der anderen auf Eigenschaften basierenden Eingaben, die Bestandteil des WPF-Systems sind, für die Eigenschaft festgelegt wurde. Abhängigkeitseigenschaftswerten werden Prioritäten zugewiesen, damit eine Vielzahl von Szenarios zur Art und Weise, wie Eigenschaften ihre Werte erhalten, in einer vorhersagbaren Weise interagieren können.

Betrachten Sie das folgende Beispiel. Das Beispiel enthält einen Stil, der für alle Schaltflächen und deren Background-Eigenschaften gilt, aber ebenso eine Schaltfläche mit einem lokal festgelegten Background-Wert angibt.

Hinweis

In der SDK-Dokumentation werden gelegentlich 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 Attribut für ein Element in XAML festgelegt wird.

Im Prinzip wird die Eigenschaft für die erste Schaltfläche zweimal festgelegt, wobei nur ein Wert angewendet wird: der Wert mit der höchsten Priorität. Ein lokal festgelegter Wert hat die höchste Priorität (außer einer ausgeführte Animation, aber auf dieses Beispiel ist keine Animation anwendbar), und der lokal festgelegte Wert wird somit anstelle des Werts des Stilsetters für den Hintergrund der ersten Schaltfläche verwendet. Die zweite Schaltfläche weist keinen lokalen Wert auf (ebenso keinen anderen Wert mit höherer Priorität als ein Stilsetter), weswegen der Hintergrund der Schaltfläche dem Stilsetter entstammt.

<StackPanel>
  <StackPanel.Resources>
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
     <Setter Property="Background" Value="Red"/>
    </Style>
  </StackPanel.Resources>
  <Button Background="Green">I am NOT red!</Button>
  <Button>I am styled red</Button>
</StackPanel>

Warum haben Abhängigkeitseigenschaften Prioritäten?

In der Regel sollen Stile nicht immer gelten und sogar einen lokal festgelegten Wert eines einzelnen Elements verdecken (andernfalls wäre es sehr schwierig, Stile oder Elemente überhaupt zu verwenden). Aus diesem Grund operieren die Werte, die von Stilen abstammen, mit einer niedrigeren Priorität als lokal festgelegte Werte. Eine ausführliche Liste der Abhängigkeitseigenschaften und Angaben dazu, woher der effektive Wert einer Abhängigkeitseigenschaft möglicherweise stammt, finden Sie unter Priorität von Abhängigkeitseigenschaftswerten.

Hinweis

Es gibt eine Reihe von Eigenschaften, die für WPF-Elemente definiert sind, die keine Abhängigkeitseigenschaften sind. Im Großen und Ganzen wurden Eigenschaften nur als Abhängigkeitseigenschaften implementiert, wenn mindestens eines der Szenarios unterstützt werden musste, das vom Eigenschaftensystem aktiviert wurde: Datenbindungen, Stile, Animationen, die standardmäßige Wertunterstützung, die Vererbung, angefügte Eigenschaften oder Invalidierungen.

Wissenswertes zu 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 (CLR)-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 beide diese Eigenschaft als Teil der Klassenmemberlisten besitzen. Ein primäres Szenario ist das Aktivieren von untergeordneten Elementen, um das übergeordnete Element darüber zu informieren, wie die untergeordneten Elemente in der Benutzeroberfläche dargestellt werden sollen. Ein Beispiel finden Sie unter Dock oder Left. Weitere Informationen finden Sie unter Übersicht über angefügte Eigenschaften.

  • 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 zu unterstützen. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften.

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

Weitere Informationen