Omówienie właściwości zależności

Program Windows Presentation Foundation (WPF) udostępnia zestaw usług, które mogą służyć do rozszerzania funkcjonalności właściwości typu. Zbiorczo te usługi są zwykle określane jako system właściwości WPF. Właściwość, która jest wspierana przez system właściwości WPF, jest nazywana właściwością zależności. W tym omówieniu opisano system właściwości WPF i możliwości właściwości zależności. Obejmuje to sposób używania istniejących właściwości zależności w języku XAML i w kodzie. W tym omówieniu przedstawiono również wyspecjalizowane aspekty właściwości zależności, takie jak metadane właściwości zależności, oraz sposób tworzenia własnej właściwości zależności w klasie niestandardowej.

Wymagania wstępne

W tym temacie założono, że masz podstawową wiedzę na temat systemu typów platformy .NET i programowania obiektowego. Aby postępować zgodnie z przykładami w tym temacie, należy również zrozumieć język XAML i wiedzieć, jak pisać aplikacje WPF. Aby uzyskać więcej informacji, zobacz Przewodnik: Moja pierwsza aplikacja klasyczna WPF.

Właściwości zależności i właściwości środowiska CLR

W WPF właściwości są zwykle uwidocznione jako standardowe właściwości platformy .NET. Na poziomie podstawowym można bezpośrednio wchodzić w interakcje z tymi właściwościami i nigdy nie wiedzieć, że są one implementowane jako właściwość zależności. Należy jednak zapoznać się z niektórymi lub wszystkimi funkcjami systemu właściwości WPF, aby móc korzystać z tych funkcji.

Celem właściwości zależności jest zapewnienie sposobu obliczenia wartości właściwości na podstawie wartości innych danych wejściowych. Te inne dane wejściowe mogą obejmować właściwości systemowe, takie jak motywy i preferencje użytkownika, mechanizmy określania właściwości just in time, takie jak powiązanie danych i animacje/scenorysy, szablony wielokrotnego użytku, takie jak zasoby i style, lub wartości znane za pomocą relacji nadrzędny-podrzędny z innymi elementami w drzewie elementów. Ponadto można zaimplementować właściwość zależności w celu zapewnienia samodzielnej weryfikacji, wartości domyślnych, wywołań zwrotnych monitorujących zmiany innych właściwości oraz systemu, który może przekształcać wartości właściwości na podstawie potencjalnie informacji o środowisku uruchomieniowym. Klasy pochodne mogą również zmieniać niektóre specyficzne cechy istniejącej właściwości, przesłaniając metadane właściwości zależności, a nie przesłaniając rzeczywistej implementacji istniejących właściwości lub tworzenia nowych właściwości.

W dokumentacji zestawu SDK można określić, która właściwość jest właściwością zależności, przez obecność sekcji Informacje o właściwości zależności na zarządzanej stronie referencyjnej dla tej właściwości. Sekcja Informacje o właściwości zależności zawiera link do DependencyProperty pola identyfikatora dla tej właściwości zależności, a także listę opcji metadanych ustawionych dla tej właściwości, informacje o zastąpieniu poszczególnych klas i inne szczegóły.

Właściwości zależności z powrotem właściwości środowiska CLR

Właściwości zależności i system właściwości WPF rozszerzają funkcjonalność właściwości, zapewniając typ, który tworzy kopię zapasową właściwości, jako alternatywną implementację standardowego wzorca tworzenia kopii zapasowej właściwości z polem prywatnym. Nazwa tego typu to DependencyProperty. Innym ważnym typem definiującym system właściwości WPF jest DependencyObject. DependencyObject definiuje klasę bazową, która może rejestrować i posiadać właściwość zależności.

Poniżej wymieniono terminologię używaną z właściwościami zależności:

  • Właściwość zależności: właściwość, która jest wspierana przez element DependencyProperty.

  • Identyfikator właściwości zależności:DependencyProperty wystąpienie, które jest uzyskiwane jako wartość zwracana podczas rejestrowania właściwości zależności, a następnie przechowywane jako statyczny element członkowski klasy. Ten identyfikator jest używany jako parametr dla wielu interfejsów API, które współdziałają z systemem właściwości WPF.

  • CLR "wrapper": rzeczywiste implementacje get i set dla właściwości. Te implementacje zawierają identyfikator właściwości zależności, używając go w wywołaniach GetValue i SetValue , zapewniając w ten sposób obsługę zapasową właściwości przy użyciu systemu właściwości WPF.

W poniższym przykładzie zdefiniowano IsSpinning właściwość zależności i pokazano relację identyfikatora DependencyProperty z właściwością, która jest wspierana.

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

Ważna jest konwencja nazewnictwa właściwości i jej pola zapasowego DependencyProperty . Nazwa pola jest zawsze nazwą właściwości z dołączonym sufiksem Property . Aby uzyskać więcej informacji na temat tej konwencji i ich przyczyn, zobacz Właściwości zależności niestandardowych.

Ustawianie wartości właściwości

Właściwości można ustawić w kodzie lub w języku XAML.

Ustawianie wartości właściwości w języku XAML

Poniższy przykład XAML określa kolor tła przycisku jako czerwony. W tym przykładzie pokazano przypadek, w którym prosta wartość ciągu atrybutu XAML jest konwertowana przez analizator XAML WPF na typ WPF (za Colorpomocą SolidColorBrushznaku ) w wygenerowanym kodzie.

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

Język XAML obsługuje różne formularze składni do ustawiania właściwości. Składnia używana dla określonej właściwości zależy od typu wartości używanego przez właściwość, a także innych czynników, takich jak obecność konwertera typów. Aby uzyskać więcej informacji na temat składni XAML dla ustawienia właściwości, zobacz XAML in WPF and XAML Syntax In Detail (Składnia XAML w języku WPF i XAML).

Jako przykład składni innej niż atrybut, poniższy przykład XAML przedstawia inne tło przycisku. Tym razem zamiast ustawiać prosty kolor stały, tło jest ustawione na obraz z elementem reprezentującym ten obraz i źródło tego obrazu określonego jako atrybut zagnieżdżonego elementu. Jest to przykład składni elementu właściwości.

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

Ustawianie właściwości w kodzie

Ustawienie wartości właściwości zależności w kodzie jest zwykle tylko wywołaniem implementacji zestawu uwidocznionej przez "otokę CLR".

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

Uzyskanie wartości właściwości jest również zasadniczo wywołaniem implementacji "otoki":

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

Możesz również wywołać interfejsy GetValue API systemu właściwości i SetValue bezpośrednio. Nie jest to zwykle konieczne, jeśli używasz istniejących właściwości (otoki są wygodniejsze i zapewniają lepszą ekspozycję właściwości dla narzędzi deweloperskich), ale bezpośrednie wywoływanie interfejsów API jest odpowiednie w niektórych scenariuszach.

Właściwości można również ustawić w języku XAML, a następnie uzyskać do ich późniejszego dostępu za pośrednictwem kodu. Aby uzyskać szczegółowe informacje, zobacz Code-Behind i XAML w WPF.

Funkcje właściwości udostępniane przez właściwość zależności

Właściwość zależności udostępnia funkcje, które rozszerzają funkcjonalność właściwości, a nie właściwość, która jest wspierana przez pole. Często takie funkcje reprezentują lub obsługują jedną z następujących określonych funkcji:

Zasoby

Wartość właściwości zależności można ustawić, odwołując się do zasobu. Zasoby są zwykle określane jako Resources wartość właściwości elementu głównego strony lub aplikacji (te lokalizacje umożliwiają najwygodniejszy dostęp do zasobu). W poniższym przykładzie pokazano, jak zdefiniować SolidColorBrush zasób.

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

Po zdefiniowaniu zasobu możesz odwoływać się do zasobu i użyć go do podania wartości właściwości:

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

Ten konkretny zasób jest przywołyny jako rozszerzenie znaczników DynamicResource (w języku WPF XAML można użyć odwołania do zasobów statycznych lub dynamicznych). Aby użyć odwołania do zasobów dynamicznych, musisz ustawić właściwość zależności, więc jest to użycie dynamicznego odwołania do zasobów, które jest włączone przez system właściwości WPF. Aby uzyskać więcej informacji, zobacz Zasoby XAML.

Uwaga

Zasoby są traktowane jako wartość lokalna, co oznacza, że jeśli ustawisz inną wartość lokalną, usuniesz odwołanie do zasobów. Aby uzyskać więcej informacji, zobacz Pierwszeństwo wartości właściwości zależności.

Powiązanie danych

Właściwość zależności może odwoływać się do wartości za pomocą powiązania danych. Powiązanie danych działa za pomocą określonej składni rozszerzenia znaczników w języku XAML lub Binding obiektu w kodzie. W przypadku powiązania danych ostateczne określenie wartości właściwości jest odroczone do czasu wykonywania, w którym wartość jest uzyskiwana ze źródła danych.

Poniższy przykład ustawia Content właściwość dla klasy Button, używając powiązania zadeklarowanego w języku XAML. Powiązanie używa dziedziczonego kontekstu danych i XmlDataProvider źródła danych (nie pokazano). Samo powiązanie określa żądaną właściwość źródłową w XPath źródle danych.

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

Uwaga

Powiązania są traktowane jako wartość lokalna, co oznacza, że jeśli ustawisz inną wartość lokalną, usuniesz powiązanie. Aby uzyskać szczegółowe informacje, zobacz Pierwszeństwo wartości właściwości zależności.

Właściwości zależności lub DependencyObject klasa nie obsługują INotifyPropertyChanged natywnie na potrzeby tworzenia powiadomień o zmianach wartości DependencyObject właściwości źródłowej dla operacji powiązania danych. Aby uzyskać więcej informacji na temat tworzenia właściwości do użycia w powiązaniu danych, które mogą zgłaszać zmiany w obiekcie docelowym powiązania danych, zobacz Omówienie powiązania danych.

Style

Style i szablony to dwa główne scenariusze motywujące do używania właściwości zależności. Style są szczególnie przydatne w przypadku ustawiania właściwości definiujących interfejs użytkownika aplikacji. Style są zwykle definiowane jako zasoby w języku XAML. Style wchodzą w interakcję z systemem właściwości, ponieważ zwykle zawierają "zestawy" dla określonych właściwości, a także "wyzwalacze", które zmieniają wartość właściwości na podstawie wartości czasu rzeczywistego dla innej właściwości.

Poniższy przykład tworzy prosty styl (który zostanie zdefiniowany wewnątrz słownika Resources , nie pokazano), a następnie stosuje ten styl bezpośrednio do Style właściwości dla elementu Button. Inicjator w stylu ustawia Background właściwość dla Button stylu na zielony.

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

Aby uzyskać więcej informacji, zobacz Styling and Templating (Styling and Templating).

Animacje

Właściwości zależności można animować. Gdy animacja jest stosowana i jest uruchomiona, animowana wartość działa na wyższym priorytecie niż dowolna wartość (na przykład wartość lokalna), którą właściwość ma w inny sposób.

Poniższy przykład animuje Background właściwość on a Button (technicznie element Background jest animowany przy użyciu składni elementu właściwości w celu określenia wartości pustej BackgroundSolidColorBrush jako , a następnie Color właściwościSolidColorBrush, która jest właściwością, która jest bezpośrednio animowana).

<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>

Aby uzyskać więcej informacji na temat animowania właściwości, zobacz Omówienie animacji i scenorysy — omówienie.

Przesłonięcia metadanych

Niektóre zachowania właściwości zależności można zmienić, przesłaniając metadane dla tej właściwości, gdy pochodzisz z klasy, która pierwotnie rejestruje właściwość zależności. Zastępowanie metadanych opiera się na identyfikatorze DependencyProperty . Zastępowanie metadanych nie wymaga ponownego implementowania właściwości. Zmiana metadanych jest obsługiwana natywnie przez system właściwości; każda klasa potencjalnie przechowuje poszczególne metadane dla wszystkich właściwości, które są dziedziczone z klas bazowych, dla poszczególnych typów.

Poniższy przykład zastępuje metadane właściwości DefaultStyleKeyzależności . Zastępowanie tych metadanych właściwości zależności jest częścią wzorca implementacji, który tworzy kontrolki, które mogą używać domyślnych stylów z motywów.

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

Aby uzyskać więcej informacji na temat zastępowania lub uzyskiwania metadanych właściwości, zobacz Metadane właściwości zależności.

Dziedziczenie wartości właściwości

Element może dziedziczyć wartość właściwości zależności od jej elementu nadrzędnego w drzewie obiektów.

Uwaga

Zachowanie dziedziczenia wartości właściwości nie jest globalnie włączone dla wszystkich właściwości zależności, ponieważ czas obliczania dziedziczenia ma pewien wpływ na wydajność. Dziedziczenie wartości właściwości jest zwykle włączone tylko dla właściwości, w których określony scenariusz sugeruje, że dziedziczenie wartości właściwości jest odpowiednie. Można określić, czy właściwość zależności dziedziczy, przeglądając sekcję Informacje o właściwości zależności dla tej właściwości zależności w dokumentacji zestawu SDK.

Poniższy przykład przedstawia powiązanie i ustawia DataContext właściwość określającą źródło powiązania, które nie zostało pokazane we wcześniejszym przykładzie powiązania. Wszystkie kolejne powiązania w obiektach podrzędnych nie muszą określać źródła, mogą używać dziedziczonej wartości z DataContext obiektu nadrzędnego StackPanel . (Alternatywnie obiekt podrzędny może zamiast tego wybrać, aby bezpośrednio określić własne DataContext lub w SourceBindingobiekcie , i celowo nie używać dziedziczonej wartości dla kontekstu danych jego powiązań).

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

Aby uzyskać więcej informacji, zobacz Dziedziczenie wartości właściwości.

Integracja projektanta WPF

Kontrolka niestandardowa z właściwościami zaimplementowanymi jako właściwości zależności otrzyma odpowiednie Projektant WPF na potrzeby obsługi programu Visual Studio. Jednym z przykładów jest możliwość edytowania właściwości zależności bezpośrednich i dołączonych za pomocą okna Właściwości . Aby uzyskać więcej informacji, zobacz Omówienie tworzenia kontrolek.

Następstwo wartości właściwości zależności

Po uzyskaniu wartości właściwości zależności potencjalnie uzyskujesz wartość ustawioną na tej właściwości za pomocą dowolnego z innych danych wejściowych opartych na właściwościach, które uczestniczą w systemie właściwości WPF. Pierwszeństwo wartości właściwości zależności istnieje, aby różne scenariusze dotyczące sposobu uzyskiwania wartości przez właściwości mogły współdziałać w przewidywalny sposób.

Rozważmy następujący przykład. Przykład zawiera styl, który ma zastosowanie do wszystkich przycisków i ich Background właściwości, ale następnie określa jeden przycisk z lokalnie ustawioną Background wartością.

Uwaga

Dokumentacja zestawu SDK używa terminów "wartość lokalna" lub "lokalnie ustawiona wartość" od czasu do czasu podczas omawiania właściwości zależności. Lokalnie ustawiona wartość to wartość właściwości ustawiana bezpośrednio na wystąpieniu obiektu w kodzie lub jako atrybut elementu w języku XAML.

W zasadzie dla pierwszego przycisku właściwość jest ustawiana dwa razy, ale ma zastosowanie tylko jedna wartość: wartość o najwyższym pierwszeństwie. Wartość ustawiona lokalnie ma najwyższy priorytet (z wyjątkiem uruchomionej animacji, ale w tym przykładzie nie ma zastosowania animacja), a zatem lokalnie ustawiona wartość jest używana zamiast wartości ustawiającej styl tła na pierwszym przycisku. Drugi przycisk nie ma wartości lokalnej (i nie ma innej wartości o wyższym priorytecie niż setter stylu), a tym samym tło w tym przycisku pochodzi z ustawiacza stylów.

<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>

Dlaczego pierwszeństwo właściwości zależności istnieje?

Zazwyczaj nie chcesz, aby style zawsze stosować i ukrywać nawet lokalnie ustawioną wartość pojedynczego elementu (w przeciwnym razie trudno byłoby użyć stylów lub elementów w ogóle). W związku z tym wartości pochodzące ze stylów działają w niższym precedensie niż wartość ustawiona lokalnie. Aby uzyskać bardziej szczegółową listę właściwości zależności i miejsca, z których może pochodzić właściwość zależności, zobacz Właściwość zależności Pierwszeństwo wartości właściwości.

Uwaga

Istnieje wiele właściwości zdefiniowanych w elementach WPF, które nie są właściwościami zależności. Przez i duże właściwości zostały zaimplementowane jako właściwości zależności tylko wtedy, gdy istniały potrzeby obsługi co najmniej jednego scenariusza włączonego przez system właściwości: powiązanie danych, styl, animacja, obsługa wartości domyślnej, dziedziczenie, dołączone właściwości lub unieważnienie.

Edukacja więcej o właściwościach zależności

  • Dołączona właściwość jest typem właściwości, która obsługuje wyspecjalizowaną składnię w języku XAML. Dołączona właściwość często nie ma korespondencji 1:1 z właściwością środowiska uruchomieniowego języka wspólnego (CLR) i nie musi być właściwością zależności. Typowym celem dołączonej właściwości jest umożliwienie elementom podrzędnym zgłaszania wartości właściwości do elementu nadrzędnego, nawet jeśli element nadrzędny i element podrzędny nie posiadają tej właściwości w ramach list składowych klasy. Jednym z podstawowych scenariuszy jest umożliwienie elementom podrzędnym informowania elementu nadrzędnego o tym, jak powinny być prezentowane w interfejsie użytkownika; na przykład zobacz Dock lub Left. Aby uzyskać szczegółowe informacje, zobacz Dołączone właściwości — omówienie.

  • Deweloperzy składników lub deweloperzy aplikacji mogą chcieć utworzyć własną właściwość zależności, aby umożliwić obsługę funkcji, takich jak powiązanie danych lub style, albo obsługa unieważnienia i wymuszania wartości. Aby uzyskać szczegółowe informacje, zobacz Właściwości zależności niestandardowych.

  • Należy wziąć pod uwagę właściwości zależności jako właściwości publiczne, dostępne lub przynajmniej wykrywalne przez dowolny obiekt wywołujący, który ma dostęp do wystąpienia. Aby uzyskać więcej informacji, zobacz Dependency Property Security (Zabezpieczenia właściwości zależności).

Zobacz też