Udostępnij za pośrednictwem


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

Program Windows Presentation Foundation (WPF) udostępnia zestaw usług, których można użyć do rozszerzenia 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.

Warunki wstępne

W tym artykule zakłada się, że czytelnik posiada podstawową wiedzę na temat systemu typów .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 Tutorial: Create a new WPF app with .NET(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 w odpowiednim momencie, takie jak wiązanie danych i animacje/scenariusze.
  • Szablony wielokrotnego użytku, takie jak zasoby i style.
  • Wartości znane za pośrednictwem relacji rodzic-dziecko z innymi elementami w drzewie elementów.

Ponadto właściwość zależności może zapewnić:

  • Niezależna walidacja.
  • Wartości domyślne.
  • Wywołania zwrotne monitorujące zmiany w innych właściwościach.
  • System, który może wymuszać wartości właściwości na podstawie informacji uzyskanych w czasie działania.

Klasy pochodne mogą modyfikować niektóre cechy istniejącej właściwości przez przesłanianie metadanych właściwości zależnej, zamiast nadpisywania rzeczywistej implementacji obecnych właściwości lub tworzenia 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 wspierające 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żna, która jest właściwością wspieraną przez DependencyProperty.

  • identyfikator właściwości zależności, czyli wystąpienie DependencyProperty uzyskane jako wartość zwracana podczas rejestrowania właściwości zależności, a następnie przechowywane 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 "wrapper", czyli 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. W ten sposób system właściwości WPF zapewnia wsparcie dla właściwości.

W poniższym przykładzie zdefiniowano właściwość zależności IsSpinning, aby pokazać związek identyfikatora DependencyProperty z właściwością, którą wspiera.

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 powiązanego pola 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 Colorprzez SolidColorBrush.

<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 WPF i składni 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ć jednolity kolor, język XAML przypisuje obraz do właściwości Background przycisku. 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 zazwyczaj po prostu wywołaniem implementacji set udostępnionej przez otoczkę CLR.

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 implementacji get "opakowania":

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

Możesz również bezpośrednio wywołać interfejsy API systemu właściwości GetValue i SetValue. 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 nich dostęp za pomocą code-behind. Aby uzyskać szczegółowe informacje, zobacz *Code-behind* i *XAML in WPF*.

Funkcjonalność właściwości udostępniana 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 definiujemy zasób SolidColorBrush:

<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 WPF XAML można użyć statycznego lub dynamicznego odwołania do zasobu. 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.

Notatka

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 kolejność 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 obiektu Binding w kodzie. W przypadku wiązania danych, określenie ostatecznej wartości właściwości jest odroczone do momentu wykonania programu, w którym wartość jest uzyskiwana ze źródła danych.

Poniższy przykład ustawia właściwość Content dla Buttonprzy użyciu powiązania zadeklarowanego w języku XAML. Powiązanie używa dziedziczonego kontekstu danych i źródła danych XmlDataProvider (nie pokazano). Wiązanie samo w sobie określa właściwość źródła w źródle danych za pomocą XPath.

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

Notatka

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 właściwości zależności.

Właściwości zależności, lub klasa DependencyObject, nie obsługują natywnie INotifyPropertyChanged dla powiadamiania o zmianach wartości właściwości źródłowej DependencyObject w operacjach 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 docelowym powiązaniu 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 właściwości Style dla Button. Setter w ramach stylu ustawia atrybut Background dla stylizowanego Button 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 Style 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 właściwość Background obiektu Button. Technicznie składnia elementu właściwości ustawia puste SolidColorBrush jako Background, a właściwość ColorSolidColorBrush 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.

Nadpisania metadanych

Właściwości zachowania zależności można zmienić, przesłaniając jej metadane, gdy pochodzi się z klasy, która pierwotnie zarejestrowała tę właściwość. Zastępowanie metadanych odbywa się za pomocą identyfikatora DependencyProperty i 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 metadane dla wszystkich właściwości dziedziczonych z klas bazowych, w zależności od typu.

Poniższy przykład zastępuje metadane właściwości zależności DefaultStyleKey. Zastępowanie metadanych dla tej konkretnej właściwości zależności stanowi część wzorca implementacji do tworzenia kontrolek umożliwiających użycie 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żnej od elementu nadrzędnego w drzewie obiektów.

Notatka

Zachowanie dziedziczenia wartości właściwości nie jest włączone globalnie 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 przedstawiono powiązanie, które zawiera właściwość DataContext w celu określenia źródła powiązania. Dlatego powiązania w obiektach podrzędnych nie muszą wskazywać źródła i mogą korzystać z dziedziczonej wartości z DataContext w nadrzędnym obiekcie StackPanel. Alternatywnie, obiekt podrzędny może bezpośrednio określić swoją własną DataContext lub Source w Binding, pomijając wartość dziedziczoną.

<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 projektantem WPF dla programu Visual Studio. Jednym z przykładów 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 kontrolki.

Pierwszeństwo wartości właściwości zależnej

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. Priorytet 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, oddziaływały w przewidywalny sposób.

Notatka

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 właściwości Background dowolnego przycisku, ale określa jeden przycisk z lokalnie ustawioną właściwością Background. Technicznie ten przycisk ma dwukrotnie ustawioną właściwość Background, chociaż ma zastosowanie tylko jedna wartość — wartość o najwyższym pierwszeństwie. 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ż ustawienie stylu, a więc używa wartości ustawienia stylu dla właściwości Background.

<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 Kolejność wartości właściwości zależności.

Notatka

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.

Dowiedz się 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żną, aby dodać możliwości, takie jak obsługa powiązań danych lub stylów, lub unieważnianie i wymuszanie 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 dependency property security.

  • 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 wspólnego języka i niekoniecznie jest 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. Aby zapoznać się z przykładami, zobacz Dock i Left. Aby uzyskać więcej informacji, zobacz Omówienie dołączonych właściwości.

Zobacz też