Pierwszeństwo wartości właściwości zależności (WPF .NET)
Działanie systemu 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.
Ważne
Dokumentacja przewodników klasycznych dla platform .NET 6 i .NET 5 (w tym .NET Core 3.1) jest w trakcie budowy.
Wymagania wstępne
W tym artykule przyjęto założenie, że masz podstawową wiedzę na temat właściwości zależności oraz że przeczytaliśmy artykuł Przegląd właściwości zależności. Aby postępować zgodnie z przykładami w tym artykule, warto zapoznać się z Extensible Application Markup Language (XAML) i dowiedzieć się, jak pisać aplikacje WPF.
System właściwości WPF
System właściwości WPF używa różnych czynników do określania wartości właściwości zależności, takich jak weryfikacja właściwości w czasie rzeczywistym, późne powiązanie i powiadomienia o zmianie właściwości dla powiązanych właściwości. Mimo że kolejność i logika używana do określania wartości właściwości zależności jest złożona, nauka jej może pomóc uniknąć niepotrzebnych ustawień właściwości, a także ustalić, dlaczego próba ustawienia właściwości zależności nie wywłaszcza oczekiwanej wartości.
Właściwości zależności ustawione w wielu miejscach
W poniższym przykładzie XAML pokazano, jak trzy różne operacje "set" Background na właściwości przycisku mogą wpływać 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 wartość Red. Jednak niejawny styl zadeklarowany w zakresie przycisku próbuje ustawić właściwość Background na .Blue A gdy wskaźnik myszy znajduje się nad przyciskiem, wyzwalacz w stylu niejawnym próbuje ustawić właściwość Background na .Yellow Z wyjątkiem koercji i animacji lokalnie ustawiona wartość właściwości ma najwyższy priorytet, więc przycisk będzie czerwony — nawet przy najechanie kursorem myszy. Jeśli jednak usuniesz lokalnie ustawioną wartość z przycisku, otrzyma ona wartość Background ze stylu. W obrębie stylu pierwszeństwo mają wyzwalacze, dlatego przycisk będzie żółty po najechanym kursorem myszy, a w przeciwnym razie niebieski. W przykładzie jest zastępowana wartość domyślna ControlTemplate przycisku, ponieważ szablon domyślny ma zakodowaną wartość myszy Background .
Lista pierwszeństwa właściwości zależności
Na poniższej liście przedstawiono ostateczną kolejność pierwszeństwa używaną 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.
Koercja systemu właściwości. Aby uzyskać więcej informacji na temat koercji, zobacz Coercion and animations (Koercja i animacje).
Aktywne animacje lub animacje z zachowaniem hold. Aby zapewnić praktyczne efekty, wartość animacji musi mieć pierwszeństwo przed wartością podstawową (niezamówioną), nawet jeśli wartość podstawowa została ustawiona lokalnie. Aby uzyskać więcej informacji, zobacz Koercja 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 SetValue przez wywołanie interfejsu API przy użyciu właściwości określonego wystąpienia. Wartość lokalna ustawiona za pomocą powiązania lub zasobu będzie mieć takie samo pierwszeństwo jak wartość, która jest ustawiana bezpośrednio.
Wartości właściwości szablonu TemplatedParent. Element ma element , 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 jest:Wyzwalaczy.
Zestawy właściwości, zazwyczaj za pośrednictwem atrybutów XAML.
Style niejawne. Dotyczy tylko właściwości Style . Wartość
Styleto dowolny zasób stylu z wartością TargetType , która pasuje do typu elementu. Zasób stylu musi istnieć na stronie lub w aplikacji. Lookup for an implicit style resource doesn't extend to styles resources in Themes (Odnośnik do niejawnego zasobu stylu nie obejmuje zasobów stylów w motywach).Wyzwalacze stylu. Wyzwalacz stylu jest wyzwalaczem w stylu jawnym lub niejawnym. Styl musi istnieć w obrębie strony lub aplikacji. Wyzwalacze w stylach domyślnych mają niższą kolejność.
Wyzwalacze szablonu. Wyzwalacz szablonu to wyzwalacz z bezpośrednio zastosowanego szablonu lub szablonu w stylu. Styl musi istnieć w obrębie strony lub aplikacji.
Wartości ustawiacze stylów. Wartość ustawiacza stylu jest wartością zastosowaną przez obiekt Setter w 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 (motyw). W stylu domyślnym kolejność pierwszeństwa jest:
Aktywne wyzwalacze.
Ustawiające.
Dziedziczenie. Niektóre właściwości zależności elementu podrzędnego dziedziczą ich 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 systemu właściwości tej właściwości. Klasy pochodne, które dziedziczą właściwość zależności, mogą przesłaniać metadane właściwości zależności (w tym wartość domyślną) na podstawie typu. 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. Dlatego jeśli właściwość dziedziczona nie jest ustawiona, zamiast domyślnej wartości elementu podrzędnego jest używana wartość domyślna elementu głównego lub nadrzędnego.
TemplatedParent
TemplatedParent Pierwszeństwo nie ma zastosowania do właściwości elementów, które są zadeklarowane bezpośrednio w standardowych znacznikach aplikacji. Koncepcja TemplatedParent istnieje tylko w przypadku elementów podrzędnych w drzewie wizualnym, które istnieją za pośrednictwem zastosowania szablonu. Gdy system właściwości wyszukuje TemplatedParent szablon określony przez element dla wartości właściwości elementu, przeszukuje szablon, który utworzył element. Wartości właściwości z szablonu TemplatedParent zazwyczaj działają tak, jakby były lokalnie ustawiane wartości w elemencie, ale z mniejszym pierwszeństwom niż rzeczywiste wartości lokalne, ponieważ szablony są potencjalnie udostępniane. Aby uzyskać więcej informacji, zobacz TemplatedParent.
Właściwość Style
Ta sama kolejność pierwszeństwa ma zastosowanie do wszystkich właściwości zależności, z wyjątkiem Style właściwości . Właściwość Style jest unikatowa, ponieważ nie może być stylowana. Koercowanie lub animowanie Style właściwości nie jest zalecane (a animowanie Style właściwości wymagałoby niestandardowej klasy animacji). W związku z tym nie wszystkie elementy pierwszeństwa mają zastosowanie. Istnieją tylko trzy sposoby ustawienia Style właściwości:
Styl jawny. Właściwość
Styleelementu jest ustawiana bezpośrednio. WartośćStylewłaściwości działa tak, jakby była wartością lokalną i ma takie samo pierwszeństwo jak element 3 na liście pierwszeństwa. 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}".Styl niejawny. Właściwość
Styleelementu nie jest ustawiana bezpośrednio. Zamiast tego styl jest stosowany, gdy istnieje na pewnym poziomie w obrębie strony lub aplikacji, i ma klucz zasobu, który odpowiada typowi elementu, do który ma zastosowanie styl, na przykład<Style TargetType="x:Type Button">. Typ musi być dokładnie taki sam, na<Style TargetType="x:Type Button">przykład nie zostanie zastosowanyMyButtondo typu, nawetMyButtonjeśli pochodzi od typuButton. WartośćStylewłaściwości ma takie samo pierwszeństwo jak element 5 na liście pierwszeństwa. Niejawną wartość stylu można wykryć, wywołując DependencyPropertyHelper.GetValueSource metodę , przekazującStylewłaściwość i sprawdzając, czy wImplicitStyleReferencewynikach.Styl domyślny, znany również jako styl motywu. Właściwość
Styleelementu nie jest ustawiana bezpośrednio. Zamiast tego pochodzi z oceny motywu środowiska uruchomieniowego przez aparat prezentacji WPF. Przed rozpoczęciem wykonywania wartośćStylewłaściwości tonull. WartośćStylewłaściwości 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.
Element ControlTemplate jest ważnym elementem w stylu domyślnym dla kontrolki. ControlTemplate jest wartością ustawianą dla właściwości Template stylu. Jeśli style domyślne nie zawierały szablonu, kontrolka bez szablonu niestandardowego jako części stylu niestandardowego nie miałaby wizualnego wyglądu. Szablon nie tylko definiuje wygląd kontrolki, ale również definiuje połączenia między właściwościami w drzewie wizualnym szablonu i odpowiednią klasą kontrolek. Każda kontrolka uwidacznia zestaw właściwości, które mogą mieć wpływ na wygląd 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 dostosowywalne właściwości. Domyślny szablon kontrolki tworzy Thumb podstawową strukturę (drzewo wizualne) z kilkoma zagnieżdżonych Border składnikami w celu utworzenia widoku fazowego. W szablonie właściwości, które mają być dostosowywane Thumb przez klasę, są udostępniane za pośrednictwem właściwości TemplateBinding. Domyślny szablon kontrolki ma różne Thumb właściwości obramowania, które współużytkują powiązanie szablonu z właściwościami takimi jak Background lub BorderThickness. Jednak tam, gdzie wartości właściwości lub układów wizualnych są zakodowane w szablonie lub są powiązane z wartościami, które pochodzą bezpośrednio z motywu, możesz zmienić tylko te wartości, zastępując cały szablon. Ogólnie rzecz biorąc, TemplateBindingjeśli właściwość pochodzi z elementu nadrzędnego z szablonem i nie jest ujmowana przez element , nie można zmienić wartości właściwości za pomocą stylów, ponieważ nie ma wygodnego sposobu jej kierowania. Jednak na właściwość może nadal mieć wpływ dziedziczenie wartości właściwości w zastosowanym szablonie lub wartość domyślna.
Style domyślne określają w TargetType swoich definicjach. Ocena motywu środowiska uruchomieniowego TargetType dopasowuje styl domyślny do DefaultStyleKey właściwości kontrolki. Z kolei zachowanie wyszukiwania niejawnych stylów używa rzeczywistego typu kontrolki. Wartość jest dziedziczona DefaultStyleKey przez klasy pochodne, więc elementy pochodne, które w przeciwnym razie mogą nie mieć skojarzonego stylu, uzyskają domyślny wygląd. Jeśli na przykład wartość pochodzi od MyButton właściwości Button, dziedziczy MyButton domyślny szablon .Button Klasy pochodne mogą zastąpić wartość domyślną elementu DefaultStyleKey w metadanych właściwości zależności. Jeśli więc potrzebujesz innej reprezentacji wizualnej dla elementu , MyButtonDefaultStyleKey możesz zastąpić metadane właściwości zależności dla elementu w pliku , a MyButtonnastępnie zdefiniować odpowiedni styl domyślny, w tym szablon, MyButton który spakuje się za pomocą kontrolki. Aby uzyskać więcej informacji, zobacz Control authoring overview (Omówienie tworzenia kontrolek).
Zasób dynamiczny
Dynamiczne odwołania do zasobów i operacje powiązania mają pierwszeństwo przed lokalizacją, w której są ustawione. Na przykład zasób dynamiczny zastosowany do wartości lokalnej ma takie samo pierwszeństwo jak element 3 na liście pierwszeństwa. Innym przykładem jest dynamiczne powiązanie zasobów zastosowane do ustawiacza właściwości w stylu domyślnym, które ma takie samo pierwszeństwo jak element 9 na liście pierwszeństwa. Ponieważ dynamiczne odwołania do zasobów i powiązanie muszą pobrać wartości ze stanu środowiska uruchomieniowego aplikacji, proces określania pierwszeństwa wartości właściwości dla dowolnej 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 ma: element do katalogu głównego strony, aplikacja, motyw, a następnie system. Aby uzyskać więcej informacji, zobacz Zasoby XAML.
Mimo że dynamiczne odwołania do zasobów i powiązania mają pierwszeństwo przed lokalizacją, w której są ustawiane, 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ąpi zasób dynamiczny lub powiązanie. Nawet jeśli wywołasz metodę ClearValue w celu wyczyszczenia lokalnie ustawionej wartości, zasób dynamiczny lub powiązanie nie zostaną przywrócone. W rzeczywistości, jeśli ClearValue wywołasz właściwość, która ma zasób dynamiczny lub powiązanie (bez wartości lokalnej literału), zasób dynamiczny lub powiązanie zostaną wyczyszone.
SetCurrentValue
Metoda SetCurrentValue jest innym sposobem ustawienia właściwości, ale nie znajduje się na liście pierwszeństwa. SetCurrentValue Umożliwia zmianę wartości właściwości bez nadpisania źródła poprzedniej wartości. Jeśli na przykład właściwość jest ustawiana przez wyzwalacz, SetCurrentValuea następnie przypiszesz inną wartość przy użyciu funkcji , następna akcja wyzwalacza ustawi właściwość z powrotem na wartość wyzwalacza. Można użyć zawsze SetCurrentValue , gdy chcesz ustawić wartość właściwości bez nadawania tej wartości poziomu pierwszeństwa wartości lokalnej. Podobnie można użyć funkcji , SetCurrentValue aby zmienić wartość właściwości bez nadpisania powiązania.
Koercja i animacja
Zarówno koercja, jak i animacja działają na wartości podstawowej. Wartość podstawowa jest wartością właściwości zależności o najwyższym priorytecie określaną przez ocenę w górę za pośrednictwem listy pierwszeństwa do momentu, gdy zostanie osiągnięty element 2.
Jeśli animacja From nie określa wartości właściwości 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 przykładową aplikację Wartości docelowe. W przykładzie dla wysokości prostokąta spróbuj ustawienie początkowych wartości lokalnych, które różnią się od dowolnej From wartości. Przykładowe animacje zaczynają się od razu przy użyciu From wartości zamiast wartości podstawowej. Po określeniu Stop wartości jako FillBehavior, po zakończeniu animacja spowoduje zresetowanie wartości właściwości do jej wartości podstawowej. Normalne pierwszeństwo jest używane do określania wartości podstawowej po zakończeniu animacji.
Do pojedynczej właściwości można zastosować wiele animacji, a każda animacja ma inne pierwszeństwo. Zamiast stosować animację o najwyższym priorytecie, aparat prezentacji WPF może zespolać wartości animacji, w zależności od sposobu, w jaki animacje zostały zdefiniowane, i typu animowanych wartości. Aby uzyskać więcej informacji, zobacz Przegląd animacji.
Koercja znajduje się na początku listy pierwszeństwa. Nawet uruchomiona animacja podlega wywłaszczaniu wartości. Niektóre istniejące właściwości zależności w WPF mają wbudowane wywłaszczanie. W przypadku niestandardowych właściwości CoerceValueCallback zależności można zdefiniować zachowanie wywłaszczania, pisząc element , który jest przekazywać jako część metadanych podczas tworzenia właściwości. Można również przesłonić zachowanie wywłaszczania istniejących właściwości, przesłaniając metadane dla tej właściwości w klasie pochodnej. Koercja wchodzi w interakcję z wartością bazową w taki sposób, że ograniczenia dotyczące koercji są stosowane w takiej sytuacji, w jaki istniały w tym czasie, ale wartość podstawowa nadal jest zachowywana. W związku z tym, jeśli ograniczenia w kolokacji zostaną później podniesione, coercion zwróci wartość najbliższą możliwej wartości bazowej, a potencjalnie wpływ wywłaszczania na właściwość przestanie obowiązywać, gdy tylko wszystkie ograniczenia zostaną podniesione. Aby uzyskać więcej informacji na temat zachowania wywłaszczania, zobacz Wywołania zwrotne właściwości zależności i walidacja.
Zachowania wyzwalacza
Kontrolki często definiują zachowania wyzwalacza w ramach ich stylu domyślnego. Ustawienie właściwości lokalnych w kontrolkach może potencjalnie powodować konflikt z tymi wyzwalaczami, uniemożliwiając wyzwalaczom odpowiadanie (wizualnie lub behawioralnie) na zdarzenia sterowane przez użytkownika. Wyzwalacz właściwości jest często spotykany w celu kontrolowania właściwości stanu, takich jak IsSelected lub IsEnabled. Na przykład domyślnie, gdy opcja jest Button wyłączona, wyzwalacz stylu motywu (IsEnabledfalseto ) ForegroundButton ustawia wartość, aby wyświetlać jako wyszaną. Jeśli ustawisz wartość lokalną Foreground , Foreground wartość właściwości lokalnej o wyższym priorytecie będzie przeważać nad wartością stylu motywu, nawet jeśli właściwość jest Button wyłączona. Podczas ustawiania wartości właściwości, które zastępują zachowania wyzwalacza na poziomie motywu dla kontrolki, należy uważać, aby nie zakłócać nadmiernie zamierzonego działania użytkownika dla tej kontrolki.
Clearvalue
Metoda ClearValue wyczyści wszystkie lokalnie zastosowane wartości właściwości zależności dla elementu. Jednak wywołanie nie ClearValue gwarantuje, że wartość domyślna ustanowiona w metadanych podczas rejestracji właściwości jest nową wartością efektywną. Wszyscy inni uczestnicy na liście pierwszeństwa są nadal aktywni i usuwana jest tylko wartość ustawiona lokalnie. Jeśli na przykład wywołasz ClearValue właściwość, która ma styl motywu, wartość stylu motywu zostanie zastosowana jako nowa wartość, a nie wartość 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, odpytując metadane właściwości zależności, SetValuea następnie lokalnie ustaw wartość właściwości za pomocą wywołania .