Omówienie właściwości zależności (WPF .NET)

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ą określane jako system właściwości WPF. Właściwość 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, w tym 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.

Ważne

Dokumentacja przewodnika dla komputerów dla platform .NET 7 i .NET 6 jest w budowie.

Wymagania wstępne

W tym artykule przyjęto założenie, że podstawowa wiedza na temat systemu typów platformy .NET i programowania obiektowego. Aby postępować zgodnie z przykładami w tym artykule, pomaga zrozumieć język XAML i wiedzieć, jak pisać aplikacje WPF. Aby uzyskać więcej informacji, zobacz Samouczek: tworzenie nowej aplikacji WPF przy użyciu platformy .NET.

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

Właściwości WPF są zwykle uwidocznione jako standardowe właściwości platformy .NET. Możesz wchodzić w interakcje z tymi właściwościami na poziomie podstawowym i nigdy nie wiedzieć, że są one implementowane jako właściwość zależności. Jednak znajomość niektórych lub wszystkich funkcji systemu właściwości WPF pomoże Ci skorzystać 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, takich jak:

  • Właściwości systemu, 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.
  • Wartości znane za pośrednictwem relacji nadrzędny-podrzędny z innymi elementami w drzewie elementów.

Ponadto właściwość zależności może zapewnić następujące elementy:

  • Samodzielna walidacja.
  • Wartości domyślne.
  • Wywołania zwrotne monitorujące zmiany w innych właściwościach.
  • System, który może przekształcać wartości właściwości na podstawie informacji o środowisku uruchomieniowym.

Klasy pochodne mogą zmieniać niektóre cechy istniejącej właściwości, przesłaniając metadane właściwości zależności, zamiast zastępować rzeczywistą implementację istniejących właściwości lub tworzenie nowych właściwości.

W dokumentacji zestawu SDK można zidentyfikować właściwość 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 pola identyfikatora DependencyProperty dla tej właściwości zależności. Zawiera również listę opcji metadanych 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 alternatywę dla 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, który definiuje klasę bazową, która może rejestrować i posiadać właściwość zależności.

Poniżej przedstawiono często używaną terminologię:

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

  • Identyfikator właściwości zależności, który jest wystąpieniem uzyskanym DependencyProperty jako wartość zwracana podczas rejestrowania właściwości zależności, a następnie przechowywany jako statyczny element członkowski klasy. Wiele interfejsów API korzystających z systemu właściwości WPF używa identyfikatora właściwości zależności jako parametru.

  • CLR "otoka", która jest get implementacją 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 . W ten sposób system właściwości WPF zapewnia obsługę zapasową właściwości.

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

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

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 ustawia kolor tła przycisku na czerwony. Wartość ciągu atrybutu XAML jest konwertowana przez analizator XAML WPF na typ WPF. W wygenerowanym kodzie typ WPF jest ColorSolidColorBrushmetodą .

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

Język XAML obsługuje kilka formularzy składni dla właściwości ustawień. Składnia używana dla określonej właściwości zależy od typu wartości używanego przez właściwość i innych czynników, takich jak obecność konwertera typów. Aby uzyskać więcej informacji na temat składni XAML dla właściwości ustawień, zobacz XAML w składni WPF i XAML Szczegółowo.

Poniższy przykład XAML przedstawia inne tło przycisku, które używa składni elementu właściwości zamiast składni atrybutu. Zamiast ustawiać prosty kolor stały, język XAML ustawia właściwość przycisku Background na obraz. Element reprezentuje ten obraz, a atrybut zagnieżdżonego elementu określa źródło obrazu.

<Button Content="I have an image background">
    <Button.Background>
        <ImageBrush ImageSource="stripes.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 set implementacji uwidocznionej przez clR "otoka":

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

Uzyskanie wartości właściwości jest zasadniczo wywołaniem get implementacji "otoki":

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

Możesz również wywołać interfejsy GetValue API systemu właściwości i SetValue bezpośrednio. Bezpośrednie wywoływanie interfejsów API jest odpowiednie w niektórych scenariuszach, ale zwykle nie w przypadku używania istniejących właściwości. Zazwyczaj otoki są wygodniejsze i zapewniają lepszą ekspozycję na właściwość dla narzędzi deweloperskich.

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 Kod-behind i XAML w WPF.

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

W przeciwieństwie do właściwości, która jest wspierana przez pole, właściwość zależności rozszerza funkcjonalność właściwości. Często dodanie funkcji reprezentuje lub obsługuje jedną z następujących 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, ponieważ te lokalizacje oferują wygodny dostęp do zasobu. W tym przykładzie SolidColorBrush zdefiniujemy zasób:

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

Teraz, gdy zasób jest zdefiniowany, możemy odwołać się do zasobu, aby podać wartość właściwości Background :

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

W języku WPF XAML można użyć statycznej lub dynamicznej dokumentacji zasobów. Ten konkretny zasób jest przywołyny jako dynamicResource. Dynamiczne odwołanie do zasobów może służyć tylko do ustawiania właściwości zależności, dlatego 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 zasobu. 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 określenie ostatecznej 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 Buttonklasy , przy użyciu 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 właściwość źródłową w źródle danych według .XPath

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

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 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 są atrakcyjnymi przyczynami 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 i "wyzwalacze", które zmieniają wartość właściwości na podstawie wartości środowiska uruchomieniowego dla innej właściwości.

Poniższy przykład tworzy prosty styl, który zostanie zdefiniowany wewnątrz słownika Resources (nie pokazano). Następnie styl jest stosowany 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}" Content="I am green"/>

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

Animacje

Właściwości zależności można animować. Po uruchomieniu zastosowanej animacji animowana wartość ma wyższy priorytet niż jakakolwiek inna wartość właściwości, w tym wartość lokalna.

Poniższy przykład animuje Background właściwość obiektu Button. Technicznie składnia elementu właściwości ustawia wartość pustą SolidColorBrush jako Background, a Color właściwość SolidColorBrush obiektu jest animowana.

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

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

Przesłonięcia metadanych

Określone zachowania właściwości zależności można zmienić, przesłaniając jego metadane, gdy pochodzisz z klasy, która pierwotnie zarejestrowała właściwość zależności. Zastępowanie metadanych opiera się na identyfikatorze DependencyProperty i nie wymaga ponownego zaimplementowania 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 dziedziczone z klas bazowych na podstawie poszczególnych typów.

Poniższy przykład zastępuje metadane właściwości DefaultStyleKey zależności. Zastępowanie metadanych dla tej konkretnej właściwości zależności jest częścią wzorca implementacji do tworzenia kontrolek, 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 dostępu do metadanych dla właściwości zależności, zobacz Zastępowanie metadanych dla 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 wpływa na wydajność. Dziedziczenie wartości właściwości jest zwykle włączone tylko w scenariuszach, które sugerują zastosowanie. Możesz sprawdzić, 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.

W poniższym przykładzie pokazano powiązanie, które zawiera DataContext właściwość w celu określenia źródła powiązania. Powiązania w obiektach podrzędnych nie muszą więc określać źródła i mogą używać dziedziczonej wartości z DataContext obiektu nadrzędnego StackPanel . Lub obiekt podrzędny może bezpośrednio określić własne DataContext lub w SourceBindingobiekcie , a nie używać dziedziczonej wartości.

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

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

Integracja projektanta WPF

Kontrolki niestandardowe z właściwościami zaimplementowanymi jako właściwości zależności dobrze integrują się z Projektant WPF dla programu Visual Studio. Przykładem jest możliwość edytowania właściwości zależności bezpośrednich i dołączonych w oknie 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

Dowolne z danych wejściowych opartych na właściwościach w systemie właściwości WPF może ustawić wartość właściwości zależności. Pierwszeństwo wartości właściwości zależności istnieje, aby różne scenariusze dotyczące sposobu, w jaki właściwości uzyskują swoje wartości w przewidywalny sposób.

Uwaga

Dokumentacja zestawu SDK czasami używa terminu "wartość lokalna" lub "lokalnie ustawiona wartość" 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 następnym przykładzie znajduje się styl, który ma zastosowanie do Background właściwości dowolnego przycisku, ale określa jeden przycisk z lokalnie ustawioną Background właściwością. Technicznie ten przycisk ma dwukrotnie Background ustawioną właściwość, chociaż ma zastosowanie tylko jedna wartość — wartość o najwyższym prioryencie. Lokalnie ustawiona wartość ma najwyższy priorytet, z wyjątkiem uruchomionej animacji, która nie istnieje tutaj. Dlatego drugi przycisk używa lokalnie ustawionej wartości właściwości Background zamiast wartości ustawiającej styl. Pierwszy przycisk nie ma wartości lokalnej ani innej wartości o wyższym priorytecie niż zestaw stylów, a więc używa wartości ustawiającej styl dla Background właściwości.

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

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

Lokalnie ustawione wartości mają pierwszeństwo przed wartościami ustawiania stylów, które obsługują lokalną kontrolę właściwości elementu. Aby uzyskać szczegółowe informacje, zobacz Pierwszeństwo wartości właściwości zależności.

Uwaga

Wiele właściwości zdefiniowanych na elementach WPF nie jest właściwościami zależności, ponieważ właściwości zależności były zwykle implementowane tylko wtedy, gdy wymagana była funkcja systemu właściwości WPF. Funkcje obejmują powiązanie danych, styl, animację, obsługę wartości domyślnej, dziedziczenie, dołączone właściwości i unieważnienie.

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

  • Deweloperzy składników lub deweloperzy aplikacji mogą chcieć utworzyć własną właściwość zależności, aby dodać możliwości, takie jak obsługa powiązania danych lub stylów, lub unieważnienie i obsługa przymusu wartości. Aby uzyskać więcej informacji, 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 wykrywalne przez dowolny obiekt wywołujący z dostępem do wystąpienia. Aby uzyskać więcej informacji, zobacz Zabezpieczenia właściwości 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 i nie musi być właściwością zależności. Głównym 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 zawierają tej właściwości w ramach list składowych klasy. Jednym z podstawowych scenariuszy jest włączenie elementu podrzędnego w celu poinformowania elementów nadrzędnych, jak je przedstawić w interfejsie użytkownika. Przykłady można znaleźć w temacie Dock i Left. Aby uzyskać więcej informacji, zobacz Omówienie dołączonych właściwości.

Zobacz też