Pierwszeństwo wartości właściwości zależności (WPF .NET)
Działanie systemu właściwości Windows Presentation Foundation (WPF) wpływa na wartość właściwości zależności. W tym artykule wyjaśniono, jak pierwszeństwo różnych danych wejściowych opartych na właściwościach w systemie właściwości WPF określa efektywną wartość właściwości zależności.
Warunki wstępne
Artykuł zakłada, że masz podstawową wiedzę na temat właściwości zależności oraz że zapoznałeś się z omówieniem właściwości zależności . Aby postępować zgodnie z przykładami w tym artykule, warto zapoznać się z językiem Extensible Application Markup Language (XAML) i wiedzieć, jak pisać aplikacje WPF.
System właściwości WPF
System właściwości WPF używa różnych czynników do określenia wartości właściwości zależności, takich jak walidacja właściwości w czasie rzeczywistym, późne powiązanie i powiadomienia o zmianie właściwości powiązanych. Mimo że kolejność i logika używana do określania wartości właściwości zależności jest złożona, uczenie się może pomóc uniknąć niepotrzebnych ustawień właściwości, a także dowiedzieć się, dlaczego próba ustawienia właściwości zależności nie spowodowało oczekiwanej wartości.
Właściwości zależności ustawione w wielu miejscach
Poniższy przykład XAML pokazuje, jak trzy różne operacje ustawienia na właściwości Background przycisku mogą mieć wpływ na jego wartość.
<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</StackPanel.Resources>
<Button Template="{StaticResource ButtonTemplate}" Background="Red">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Which color do you expect?
</Button>
</StackPanel>
W tym przykładzie właściwość Background
jest lokalnie ustawiona na Red
. Jednak niejawny styl zadeklarowany w zakresie przycisku próbuje ustawić właściwość Background
na Blue
. A kiedy mysz jest nad przyciskiem, wyzwalacz w niejawnym stylu próbuje ustawić właściwość Background
na Yellow
. Z wyjątkiem wymuszania i animacji, lokalnie ustawiona wartość właściwości ma najwyższy priorytet, więc przycisk będzie czerwony — nawet po najechaniu kursorem. Jeśli jednak usuniesz lokalnie ustawioną wartość z przycisku, otrzyma on wartość Background
ze stylu. W obrębie stylu wyzwalacze mają pierwszeństwo, więc przycisk będzie żółty po najechaniu kursorem myszy, a w pozostałych przypadkach niebieski. Przykład zamienia domyślną wartość ControlTemplate przycisku, ponieważ domyślny szablon ma z góry ustaloną wartość Background
efektu najechania myszką.
Lista priorytetów właściwości zależnych
Poniższa lista to ostateczna kolejność pierwszeństwa używana przez system właściwości podczas przypisywania wartości środowiska uruchomieniowego do właściwości zależności. Najwyższy priorytet jest wymieniony jako pierwszy.
wymuszanie systemu właściwości. Aby uzyskać więcej informacji na temat przymusu, zobacz Coercion i animacje.
aktywne animacje lub animacje z zachowaniem blokady. Aby wywrzeć praktyczny wpływ, wartość animacji musi mieć pierwszeństwo przed wartością podstawową (nieanimowaną), nawet jeśli wartość podstawowa została ustawiona lokalnie. Aby uzyskać więcej informacji, zobacz Coercion i animacje.
wartości lokalne. Wartość lokalną można ustawić za pomocą właściwości "otoki", która odpowiada ustawieniu atrybutu lub elementu właściwości w języku XAML, lub przez wywołanie interfejsu API SetValue przy użyciu właściwości określonego wystąpienia. Wartość lokalna ustawiona za pomocą powiązania lub zasobu będzie miała taki sam priorytet jak wartość, która jest ustawiana bezpośrednio.
wartości właściwości szablonu TemplatedParent. Element ma TemplatedParent, jeśli został utworzony przez szablon (ControlTemplate lub DataTemplate). Aby uzyskać więcej informacji, zobacz TemplatedParent. W szablonie określonym przez
TemplatedParent
kolejność pierwszeństwa to:Wyzwalacze.
Zestawy właściwości, zazwyczaj za pomocą atrybutów XAML.
Niejawne style. Dotyczy tylko właściwości Style. Wartość
Style
to dowolny zasób stylu z wartością TargetType zgodną z typem elementu. Zasób stylu musi istnieć w obrębie strony lub aplikacji. Wyszukiwanie niejawnego zasobu stylu nie rozszerza się na zasoby stylów w motywach.Wyzwalacze stylu. Wyzwalacz stylu jest wyzwalaczem w jawnym lub niejawnym stylu. Styl musi istnieć w obrębie strony lub aplikacji. Wyzwalacze w stylach domyślnych mają niższy priorytet.
Wyzwalacze szablonu . Wyzwalacz szablonu to wyzwalacz pochodzący z bezpośrednio zastosowanego szablonu lub z szablonu zawartego w stylu. Styl musi istnieć w obrębie strony lub aplikacji.
wartości ustawiania stylów. Wartość wyznaczająca styl to wartość zastosowana przez element Setter w ramach stylu. Styl musi istnieć w obrębie strony lub aplikacji.
style domyślne, znane również jako style motywu . Aby uzyskać więcej informacji, zobacz Style domyślne (Temat) . W domyślnym stylu kolejność pierwszeństwa to:
Aktywne wyzwalacze.
Ustawiające.
dziedziczenie. Niektóre właściwości zależności elementu podrzędnego dziedziczą swoją wartość z elementu nadrzędnego. Dlatego może nie być konieczne ustawienie wartości właściwości dla każdego elementu w całej aplikacji. Aby uzyskać więcej informacji, zobacz dziedziczenie wartości właściwości.
Wartość domyślna z metadanych właściwości zależności Właściwość zależności może mieć wartość domyślną ustawioną podczas rejestracji w systemie właściwości. Klasy pochodne dziedziczące właściwość zależności mogą zastąpić metadane właściwości zależności (w tym wartość domyślna) dla poszczególnych typów. Aby uzyskać więcej informacji, zobacz metadane właściwości zależności . W przypadku właściwości dziedziczonej wartość domyślna elementu nadrzędnego ma pierwszeństwo przed wartością domyślną elementu podrzędnego. Jeśli więc właściwość dziedziczona nie jest ustawiona, zostanie użyta domyślna wartość elementu głównego lub nadrzędnego zamiast wartości domyślnej elementu podrzędnego.
SzablonowyRodzic
TemplatedParent priorytet nie ma zastosowania do właściwości elementów, które są zadeklarowane bezpośrednio w standardowych znacznikach aplikacji. Koncepcja TemplatedParent
istnieje tylko dla elementów podrzędnych w drzewie wizualnym, które wchodzą w życie za pośrednictwem aplikacji szablonu. Gdy system właściwości przeszukuje szablon określony przez TemplatedParent
dla wartości właściwości elementu, to przeszukuje on szablon, który utworzył ten element. Wartości właściwości z szablonu TemplatedParent
zazwyczaj działają tak, jakby były lokalnie ustawionymi wartościami w elemencie, ale z mniejszym priorytetem niż rzeczywiste lokalne wartości, gdyż szablony mogą być udostępniane. Aby uzyskać więcej informacji, zobacz TemplatedParent.
Właściwość Styl
Ta sama kolejność pierwszeństwa ma zastosowanie do wszystkich właściwości zależności, z wyjątkiem właściwości Style. Właściwość Style
jest unikatowa, ponieważ nie może być stylizowana. Wymuszanie lub animowanie właściwości Style
nie jest zalecane (i animowanie właściwości Style
wymaga niestandardowej klasy animacji). W związku z tym nie wszystkie elementy pierwszeństwa mają zastosowanie. Istnieją tylko trzy sposoby ustawiania właściwości Style
:
Styl explicytny. Właściwość
Style
elementu jest ustawiana bezpośrednio. Wartość właściwościStyle
działa tak, jak gdyby była wartością lokalną i ma taki sam priorytet jak element 3 na liście priorytetów . W większości scenariuszy jawne style nie są zdefiniowane w tekście i zamiast tego są jawnie przywołyne jako zasób, na przykładStyle="{StaticResource myResourceKey}"
.Niejawny styl. Właściwość
Style
elementu nie jest ustawiana bezpośrednio. Zamiast tego styl jest stosowany, gdy istnieje na pewnym poziomie strony lub aplikacji, i ma klucz zasobu zgodny z typem elementu, którego dotyczy styl, na przykład<Style TargetType="x:Type Button">
. Typ musi być dokładnie zgodny, na przykład<Style TargetType="x:Type Button">
nie zostanie zastosowany do typuMyButton
, nawet jeśliMyButton
pochodzi zButton
. Wartość właściwościStyle
ma taki sam priorytet jak element 5 na liście pierwszeństwa . Można wykryć niejawną wartość stylu, wywołując metodę DependencyPropertyHelper.GetValueSource, przekazując właściwośćStyle
i sprawdzającImplicitStyleReference
w wynikach.styl domyślny, znany również jako styl motywu . Właściwość
Style
elementu nie jest ustawiana bezpośrednio. Zamiast tego pochodzi z oceny motywu środowiska uruchomieniowego przez aparat prezentacji WPF. Przed uruchomieniem wartość właściwościStyle
jestnull
. Wartość właściwościStyle
ma takie samo pierwszeństwo jak element 9 na liście pierwszeństwa .
Style domyślne (motyw)
Każda kontrolka dostarczana z WPF ma domyślny styl, który może się różnić w zależności od motywu, dlatego styl domyślny jest czasami określany jako styl motywu .
ControlTemplate jest ważnym elementem w domyślnym stylu kontrolki.
ControlTemplate
jest wartością ustawiającą dla właściwości Template stylu. Jeśli style domyślne nie zawierają szablonu, kontrolka bez szablonu niestandardowego w ramach stylu niestandardowego nie będzie miała wyglądu wizualnego. Szablon nie tylko definiuje wygląd wizualizacji kontrolki, ale także definiuje połączenia między właściwościami w drzewie wizualnym szablonu i odpowiednią klasą sterowania. Każda kontrolka uwidacznia zestaw właściwości, które mogą wpływać na wygląd wizualizacji kontrolki bez zastępowania szablonu. Rozważmy na przykład domyślny wygląd kontrolki Thumb, która jest składnikiem ScrollBar.
Kontrolka Thumb ma pewne właściwości, które można dostosowywać. Domyślny szablon kontrolki Thumb
tworzy podstawową strukturę drzewa wizualnego z kilkoma zagnieżdżonymi składnikami Border w celu utworzenia skośnego wyglądu. W szablonie właściwości, które mają być dostosowywalne przez klasę Thumb
, są udostępniane za pośrednictwem TemplateBinding. Domyślny szablon kontrolki Thumb
ma różne właściwości obramowania, które mają powiązanie szablonu z właściwościami, takimi jak Background lub BorderThickness. Jednak jeśli wartości właściwości lub ustaleń wizualnych są zakodowane w szablonie lub są powiązane z wartościami pochodzącymi bezpośrednio z motywu, można zmienić tylko te wartości, zastępując cały szablon. Ogólnie rzecz biorąc, jeśli właściwość pochodzi z szablonu nadrzędnego i nie jest udostępniona przez TemplateBinding
, nie można zmienić wartości właściwości za pomocą stylów, ponieważ nie ma wygodnego sposobu, aby ją odnieść. Jednak na tę właściwość nadal może mieć wpływ dziedziczenie wartości w zastosowanym szablonie lub wartość domyślna.
Style domyślne określają TargetType w swoich definicjach. Ocena motywu środowiska uruchomieniowego jest zgodna z TargetType
stylu domyślnego do właściwości DefaultStyleKey kontrolki. Natomiast zachowanie wyszukiwania w przypadku stylów niejawnych używa rzeczywistego typu kontrolki. Wartość DefaultStyleKey
jest dziedziczona przez klasy pochodne, dzięki czemu elementy pochodne, które w przeciwnym razie nie miałyby skojarzonego stylu, otrzymują domyślny wygląd wizualny. Jeśli na przykład utworzysz MyButton
z Button, MyButton
odziedziczy domyślny szablon Button
. Klasy pochodne mogą zastąpić wartość domyślną DefaultStyleKey
w metadanych właściwości zależności. Dlatego jeśli chcesz innej reprezentacji wizualnej dla MyButton
, możesz zastąpić metadane właściwości zależności dla DefaultStyleKey
na MyButton
, a następnie zdefiniować odpowiedni styl domyślny, w tym szablon, który spakujesz za pomocą kontrolki MyButton
. Aby uzyskać więcej informacji, zobacz omówienie tworzenia kontrolek Control.
Zasób dynamiczny
dynamiczne odwołania i operacje powiązań mają pierwszeństwo przed lokalizacją, w której są ustawione. Na przykład zasób dynamiczny zastosowany do wartości lokalnej ma taki sam priorytet jak pozycja 3 na liście priorytetów . Jako inny przykład, dynamiczne wiązanie zasobów zastosowane do ustawienia właściwości w obrębie stylu domyślnego ma taki sam priorytet jak pozycja 9 na liście priorytetów . Ponieważ dynamiczne odwołania do zasobów i powiązanie muszą pobierać wartości ze stanu środowiska uruchomieniowego aplikacji, proces określania pierwszeństwa wartości właściwości dla każdej danej właściwości rozszerza się na środowisko uruchomieniowe.
Odwołania do zasobów dynamicznych nie są technicznie częścią systemu właściwości i mają własną kolejność wyszukiwania, która współdziała z listą pierwszeństwa . Zasadniczo pierwszeństwo odwołań do zasobów dynamicznych to: element do strony głównej, aplikacji, motywu, a następnie systemu. Aby uzyskać więcej informacji, zobacz zasoby XAML .
Mimo że odwołania do zasobów dynamicznych i powiązania mają pierwszeństwo przed lokalizacją, w której są ustawione, wartość jest odroczona. Jedną z konsekwencji jest to, że jeśli ustawisz zasób dynamiczny lub powiązanie z wartością lokalną, każda zmiana wartości lokalnej całkowicie zastępuje zasób dynamiczny lub powiązanie. Nawet jeśli wywołasz metodę ClearValue w celu wyczyszczenia wartości ustawionej lokalnie, nie zostanie przywrócony zasób dynamiczny lub powiązanie. W rzeczywistości jeśli wywołasz ClearValue
dla właściwości, która ma zasób dynamiczny lub powiązanie (bez wartości dosłownej lokalnej), zasób dynamiczny lub powiązanie zostaną wyczyszczone.
UstawAktualnąWartość
Metoda SetCurrentValue to inny sposób ustawiania właściwości, ale nie znajduje się na liście pierwszeństwa .
SetCurrentValue
umożliwia zmianę wartości właściwości bez zastępowania źródła poprzedniej wartości. Jeśli na przykład właściwość jest ustawiana przez wyzwalacz, a następnie przypiszesz inną wartość przy użyciu SetCurrentValue
, następna akcja wyzwalacza ustawi właściwość z powrotem na wartość wyzwalacza. Możesz użyć SetCurrentValue
zawsze, gdy chcesz ustawić wartość właściwości bez podawania tej wartości poziomu pierwszeństwa wartości lokalnej. Podobnie można użyć SetCurrentValue
, aby zmienić wartość właściwości, nie nadpisując istniejącego powiązania.
Przymus i animacja
Przymus i animacja działają na wartości bazowej . Wartość podstawowa jest wartością właściwości zależności o najwyższym prioryencie określonym przez ocenę w górę przez listę pierwszeństwa do momentu osiągnięcia pozycji 2.
Jeśli animacja nie określa zarówno wartości właściwości From, jak i To dla niektórych zachowań lub jeśli animacja celowo przywraca wartość podstawową po zakończeniu, wartość podstawowa może mieć wpływ na animowaną wartość. Aby zobaczyć to w praktyce, uruchom aplikację przykładową Wartości Docelowe. W przykładzie dla wysokości prostokąta spróbuj ustawić początkowe wartości lokalne, które różnią się od dowolnej wartości From
. Przykładowe animacje zaczynają się od razu przy użyciu wartości From
zamiast wartości podstawowej. Określając Stop jako FillBehavior, po zakończeniu animacja spowoduje zresetowanie wartości właściwości do jej wartości bazowej. Normalne reguły pierwszeństwa są stosowane dla określenia wartości bazowej po zakończeniu animacji.
Do jednej właściwości można zastosować wiele animacji, a każda animacja ma inne pierwszeństwo. Zamiast stosować animację z najwyższym priorytetem, aparat prezentacji WPF może składać wartości animacji, w zależności od sposobu definiowania animacji i typu animowanych wartości. Aby uzyskać więcej informacji, zobacz omówienie animacji .
Coercion znajduje się u góry listy pierwszeństwa . Nawet uruchomiona animacja podlega przymusowi wartości. Niektóre istniejące właściwości zależności w WPF mają wbudowane wymuszanie. W przypadku właściwości zależności niestandardowych można zdefiniować zachowanie przymusu, zapisując CoerceValueCallback przekazywane jako część metadanych podczas tworzenia właściwości. Można również zmienić sposób wymuszania istniejących właściwości, modyfikując metadane dla tej właściwości w klasie pochodnej. Przymus wchodzi w interakcję z wartością bazową w taki sposób, że ograniczenia przymusu są stosowane w miarę ich istnienia w tym czasie, ale wartość podstawowa jest nadal zachowywana. W rezultacie, jeśli ograniczenia wymuszenia zostaną później zniesione, wymuszenie zwróci wartość możliwie najbliższą wartości bazowej, a jego wpływ na właściwość może przestać obowiązywać natychmiast po zniesieniu wszystkich ograniczeń. Aby uzyskać więcej informacji na temat zachowania przymusu, zobacz wywołania zwrotne właściwości zależności i walidacji.
Zachowania wyzwalacza
Kontrolki często definiują zachowania wyzwalacza w ramach stylu domyślnego. Ustawienie właściwości lokalnych kontrolek może potencjalnie powodować konflikt z tymi wyzwalaczami, uniemożliwiając wyzwalacze reagowania (wizualnie lub behawioralnie) na zdarzenia sterowane przez użytkownika. Typowym zastosowaniem wyzwalacza właściwości jest kontrolowanie właściwości stanu, takich jak IsSelected lub IsEnabled. Na przykład, domyślnie, gdy Button jest wyłączona, wyzwalacz stylu motywu (IsEnabled
jest false
) ustawia wartość Foreground, aby Button
wyglądała na wyszarzoną. Jeśli ustawiono lokalną wartość Foreground
, lokalna wartość właściwości o wyższym priorytecie zastąpi wartość Foreground
stylu motywu, nawet gdy Button
jest wyłączona. Podczas ustawiania wartości właściwości, które zastępują zachowania wyzwalacza na poziomie motywu dla kontrolki, należy zachować ostrożność, aby nie zakłócać zamierzonego doświadczenia użytkownika dla tej kontrolki.
ClearValue
Metoda ClearValue czyści wszelkie lokalnie zastosowane wartości właściwości zależności dla elementu. Jednak wywołanie ClearValue
nie gwarantuje, że wartość domyślna ustanowiona w metadanych podczas rejestracji właściwości jest nową obowiązującą wartością. Wszyscy inni uczestnicy listy pierwszeństwa są nadal aktywni, a tylko lokalnie ustawiona wartość zostanie usunięta. Jeśli na przykład wywołasz ClearValue
dla właściwości, która ma styl motywu, wartość stylu motywu zostanie zastosowana jako nowa wartość, a nie domyślna oparta na metadanych. Jeśli chcesz ustawić wartość właściwości na wartość domyślną zarejestrowanych metadanych, pobierz domyślną wartość metadanych, wykonując zapytanie dotyczące metadanych właściwości zależności, a następnie lokalnie ustaw wartość właściwości za pomocą wywołania SetValue.
Zobacz też
.NET Desktop feedback