Udostępnij za pośrednictwem


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

W tym temacie wyjaśniono, jak działanie systemu właściwości Windows Presentation Foundation (WPF) może mieć wpływ na wartość właściwości zależności i opisuje pierwszeństwo, w którym aspekty systemu właściwości mają zastosowanie do obowiązującej wartości właściwości.

Wymagania wstępne

W tym temacie założono, że rozumiesz właściwości zależności z perspektywy konsumenta istniejących właściwości zależności w klasach WPF i zapoznaj się z tematem Właściwości zależności — omówienie. Aby postępować zgodnie z przykładami w tym temacie, należy również zrozumieć język XAML i wiedzieć, jak pisać aplikacje WPF.

System właściwości WPF

System właściwości WPF oferuje zaawansowany sposób określania wartości właściwości zależności przez różne czynniki, włączając funkcje, takie jak walidacja właściwości w czasie rzeczywistym, późne powiązanie i powiadamianie powiązanych właściwości o zmianach wartości dla innych właściwości. Dokładna kolejność i logika używana do określania wartości właściwości zależności jest dość złożona. Znajomość tej kolejności pomoże uniknąć niepotrzebnego ustawienia właściwości, a także może wyjaśnić zamieszanie dotyczące dokładnie tego, dlaczego niektóre próby wywierania wpływu lub przewidywania wartości właściwości zależności nie zakończyły się wynikiem oczekiwanej wartości.

Właściwości zależności mogą być "ustawione" w wielu miejscach

Poniżej przedstawiono przykładowy kod XAML, w którym ta sama właściwość (Background) ma trzy różne operacje "set", które mogą mieć wpływ na 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 miejscu spodziewany kolor będzie stosowany — czerwony, zielony lub niebieski?

Z wyjątkiem animowanych wartości i przymusu lokalne zestawy właściwości są ustawiane na najwyższym priorytecie. Jeśli ustawisz wartość lokalnie, możesz oczekiwać, że wartość zostanie honorowana, nawet powyżej wszystkich stylów lub szablonów kontrolek. W tym przykładzie Background ustawiono wartość Czerwony lokalnie. W związku z tym styl zdefiniowany w tym zakresie, mimo że jest to niejawny styl, który w przeciwnym razie ma zastosowanie do wszystkich elementów tego typu w tym zakresie, nie jest najwyższym priorytetem dla nadania Background właściwości jej wartości. Jeśli usunięto lokalną wartość Red z tego wystąpienia przycisku, styl będzie miał pierwszeństwo, a przycisk uzyska wartość Tło ze stylu. W obrębie stylu wyzwalacze mają pierwszeństwo, więc przycisk będzie niebieski, jeśli mysz się na nim znajduje, a w przeciwnym razie zielony.

Lista pierwszeństwa ustawień właściwości zależności

Poniżej przedstawiono ostateczną kolejność, która jest używana przez system właściwości podczas przypisywania wartości czasu wykonywania właściwości zależności. Najwyższy priorytet jest wymieniony jako pierwszy. Ta lista rozszerza niektóre uogólnienia dokonane w przeglądzie właściwości zależności.

  1. Przymus systemu właściwości. Aby uzyskać szczegółowe informacje na temat przymusu, zobacz Coercion, Animation i Base Value w dalszej części tego tematu.

  2. Aktywne animacje lub animacje z zachowaniem blokady. Aby mieć jakikolwiek praktyczny efekt, animacja właściwości musi mieć pierwszeństwo przed wartością podstawową (bez odpowiedzi), nawet jeśli ta wartość została ustawiona lokalnie. Aby uzyskać szczegółowe informacje, zobacz Coercion, Animation i Base Value w dalszej części tego tematu.

  3. Wartość lokalna. Wartość lokalna może być ustawiana za pośrednictwem wygody właściwości "otoki", która również odpowiada ustawieniu jako atrybutu lub elementu właściwości w języku XAML lub przez wywołanie interfejsu SetValue API przy użyciu właściwości określonego wystąpienia. Jeśli ustawisz wartość lokalną przy użyciu powiązania lub zasobu, każdy z nich działa w pierwszeństwie tak, jakby wartość bezpośrednia została ustawiona.

  4. Właściwości szablonu szablon Element ma TemplatedParent wartość , jeśli została utworzona jako część szablonu (a ControlTemplate lub DataTemplate). Aby uzyskać szczegółowe informacje na temat tego, kiedy to dotyczy, zobacz SzablondParent w dalszej części tego tematu. W szablonie obowiązują następujące pierwszeństwo:

    1. Wyzwalacze z szablonu TemplatedParent .

    2. Zestawy właściwości (zazwyczaj za pomocą atrybutów XAML) w szablonie TemplatedParent .

  5. Niejawny styl. Dotyczy tylko Style właściwości . Właściwość Style jest wypełniana przez dowolny zasób stylu z kluczem zgodnym z typem tego elementu. Ten zasób stylu musi istnieć na stronie lub w aplikacji; Wyszukiwanie niejawnego zasobu stylu nie powoduje przejścia do motywów.

  6. Wyzwalacze stylu. Wyzwalacze w stylach ze strony lub aplikacji (te style mogą być jawne lub niejawne, ale nie ze stylów domyślnych, które mają niższy priorytet).

  7. Wyzwalacze szablonu. Dowolny wyzwalacz z szablonu w stylu lub bezpośrednio zastosowany szablon.

  8. Zestawy stylów. Wartości z poziomu Setter stylów ze strony lub aplikacji.

  9. Domyślny (motyw) styl. Aby uzyskać szczegółowe informacje na temat tego, kiedy ma to zastosowanie, oraz sposobu, w jaki style motywu odnoszą się do szablonów w ramach stylów motywu, zobacz Domyślne style (motyw) w dalszej części tego tematu. W domyślnym stylu ma zastosowanie następująca kolejność pierwszeństwa:

    1. Aktywne wyzwalacze w stylu motywu.

    2. Ustawiacze w stylu motywu.

  10. Dziedziczenia. Kilka właściwości zależności dziedziczy ich wartości z elementu nadrzędnego na elementy podrzędne, tak aby nie były one ustawiane specjalnie dla każdego elementu w całej aplikacji. Aby uzyskać szczegółowe informacje, zobacz Dziedziczenie wartości właściwości.

  11. Wartość domyślna z metadanych właściwości zależności. Każda dana właściwość zależności może mieć wartość domyślną ustanowioną przez rejestrację systemu właściwości tej konkretnej właściwości. Ponadto klasy pochodne dziedziczące właściwość zależności mają możliwość zastąpienia tych metadanych (w tym wartości domyślnej) dla poszczególnych typów. Aby uzyskać więcej informacji, zobacz Metadane właściwości zależności. Ponieważ dziedziczenie jest sprawdzane przed wartością domyślną, dla właściwości dziedziczonej wartość domyślna elementu nadrzędnego ma pierwszeństwo przed elementem podrzędnym. W związku z tym, jeśli właściwość dziedziczona nie jest ustawiona nigdzie, wartość domyślna określona w katalogu głównym lub nadrzędnym jest używana zamiast wartości domyślnej elementu podrzędnego.

Szablonyparent

SzablondParent jako element pierwszeństwa nie ma zastosowania do żadnej właściwości elementu zadeklarowanego bezpośrednio w standardowym znaczniku 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 wyszukuje TemplatedParent szablon dla wartości, wyszukuje szablon, który utworzył ten element. Wartości właściwości z szablonu TemplatedParent zwykle działają tak, jakby zostały ustawione jako wartość lokalna w elemencie podrzędnym, ale ten mniejszy priorytet w porównaniu z wartością lokalną istnieje, ponieważ szablony są potencjalnie udostępniane. Aby uzyskać szczegółowe informacje, zobacz TemplatedParent.

Właściwość Style

Kolejność wyszukiwania opisanego wcześniej dotyczy wszystkich możliwych właściwości zależności, z wyjątkiem jednej: Style właściwości . Właściwość Style jest unikatowa w tym, że nie może być stylizowany, więc pierwszeństwo elementów od 5 do 8 nie ma zastosowania. Ponadto animowanie lub konercing Style nie jest zalecane (a animowanie Style wymaga niestandardowej klasy animacji). Pozostawia to trzy sposoby Style ustawiania właściwości:

  • Styl jawny. Właściwość Style jest ustawiana bezpośrednio. W większości scenariuszy styl nie jest zdefiniowany w tekście, ale zamiast tego jest przywołyny jako zasób za pomocą klucza jawnego. W tym przypadku właściwość Style działa tak, jakby była to wartość lokalna, pierwszeństwo elementu 3.

  • Niejawny styl. Właściwość Style nie jest ustawiana bezpośrednio. Jednak element Style istnieje na pewnym poziomie w sekwencji wyszukiwania zasobów (strona, aplikacja) i jest kluczem przy użyciu klucza zasobu zgodnego z typem, do którego ma zostać zastosowany styl. W tym przypadku Style sama właściwość działa zgodnie z pierwszeństwem określonym w sekwencji jako element 5. Ten warunek można wykryć za pomocą właściwości DependencyPropertyHelperStyle i wyszukać ImplicitStyleReference w wynikach.

  • Styl domyślny, znany również jako styl motywu. Właściwość Style nie jest ustawiana bezpośrednio, a w rzeczywistości będzie odczytywana jako null do czasu wykonywania. W tym przypadku styl pochodzi z oceny motywu czasu wykonywania, która jest częścią aparatu prezentacji WPF.

W przypadku niejawnych stylów, których nie ma w motywach, typ musi być dokładnie zgodny — MyButtonButtonklasa pochodna nie będzie niejawnie używać stylu dla klasy Button.

Style domyślne (motyw)

Każda kontrolka dostarczana z WPF ma domyślny styl. Ten domyślny styl może się różnić w zależności od motywu, dlatego ten domyślny styl jest czasami określany jako styl motywu.

Najważniejsze informacje, które znajdują się w domyślnym stylu kontrolki, to szablon kontrolki, który istnieje w stylu motywu jako element ustawiający dla jego Template właściwości. Jeśli nie ma szablonu ze stylów domyślnych, kontrolka bez szablonu niestandardowego w ramach stylu niestandardowego nie będzie miała żadnego wyglądu wizualnego. Szablon ze stylu domyślnego udostępnia wizualizację każdej kontrolki podstawową strukturę, a także definiuje połączenia między właściwościami zdefiniowanymi w drzewie wizualnym szablonu i odpowiednią klasą kontrolki. Każda kontrolka uwidacznia zestaw właściwości, które mogą wpływać na wygląd wizualizacji kontrolki bez całkowitego zastępowania szablonu. Rozważmy na przykład domyślny wygląd kontrolki Thumb , która jest składnikiem elementu ScrollBar.

Element Thumb ma pewne właściwości możliwe do dostosowania. Domyślny szablon tworzy Thumb podstawową strukturę / drzewo wizualne z kilkoma zagnieżdżonym Border składnikami, aby utworzyć wygląd skosu. Jeśli właściwość, która jest częścią szablonu, ma być uwidoczniona do dostosowania przez Thumb klasę, ta właściwość musi być uwidoczniona przez szablon TemplateBinding. W przypadku programu Thumbróżne właściwości tych obramowań współużytkować powiązanie szablonu z właściwościami, takimi jak Background lub BorderThickness. Jednak niektóre inne właściwości lub układy wizualne są zakodowane w szablonie kontrolki lub są powiązane z wartościami pochodzącymi bezpośrednio z motywu i nie można ich zmienić w zamian za pomocą całego szablonu. Ogólnie rzecz biorąc, jeśli właściwość pochodzi z szablonowego elementu nadrzędnego i nie jest uwidaczniona przez powiązanie szablonu, nie można go dostosować według stylów, ponieważ nie ma łatwego sposobu na jej określenie. Jednak ta właściwość nadal może mieć wpływ na dziedziczenie wartości właściwości w zastosowanym szablonie lub domyślnie.

Style motywu używają typu jako klucza w definicjach. Jednak gdy motywy są stosowane do danego wystąpienia elementu, wyszukiwanie motywów dla tego typu jest wykonywane przez sprawdzenie DefaultStyleKey właściwości w kontrolce. Jest to w przeciwieństwie do używania typu literału, jak robią niejawne style. Wartość klasy pochodnej DefaultStyleKey dziedziczyłaby do klas pochodnych, nawet jeśli implementator go nie zmienił (zamierzonym sposobem zmiany właściwości nie jest zastąpienie jej na poziomie właściwości, ale zamiast tego zmienić jego wartość domyślną w metadanych właściwości). Ta pośrednia umożliwia klasom bazowym zdefiniowanie stylów motywu dla elementów pochodnych, które w inny sposób nie mają stylu (lub co ważniejsze, nie mają szablonu w tym stylu i w związku z tym nie mają w ogóle domyślnego wyglądu wizualizacji). W związku z tym można pochodzić MyButton z Button szablonu domyślnego Button i nadal będzie go pobierać. Jeśli jesteś autorem kontrolki MyButton i chcesz innego zachowania, możesz zastąpić metadane właściwości zależności dla DefaultStyleKey polecenia , MyButton aby zwrócić inny klucz, a następnie zdefiniować odpowiednie style motywu, w tym szablon, MyButton który musisz spakować za pomocą MyButton kontrolki. Aby uzyskać więcej informacji na temat motywów, stylów i tworzenia kontrolek, zobacz Omówienie tworzenia kontrolek.

Odwołania i powiązania zasobów dynamicznych

Dynamiczne odwołania do zasobów i operacje powiązań są zgodne z pierwszeństwem lokalizacji, w której są ustawione. Na przykład zasób dynamiczny zastosowany do wartości lokalnej działa zgodnie z elementem pierwszeństwa 3, powiązanie dla elementu ustawiania właściwości w stylu motywu ma zastosowanie w poprzednim elemencie 9 itd. Ponieważ dynamiczne odwołania do zasobów i powiązanie muszą być w stanie uzyskać wartości ze stanu czasu wykonywania aplikacji, oznacza to, że rzeczywisty proces określania pierwszeństwa wartości właściwości dla każdej danej właściwości rozciąga się również na czas wykonywania.

Odwołania do zasobów dynamicznych nie są ściśle mówiąc częścią systemu właściwości, ale mają kolejność odnośników, która współdziała z sekwencją wymienioną powyżej. Ten priorytet został dokładniej opisany w zasobach XAML. Podstawowe podsumowanie tego pierwszeństwa to: element do strony głównej, aplikacji, motywu, systemu.

Zasoby dynamiczne i powiązania mają pierwszeństwo przed tym, gdzie zostały ustawione, ale 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 spowoduje całkowite zastąpienie zasobu dynamicznego lub powiązania. Nawet jeśli wywołasz metodę ClearValue w celu wyczyszczenia wartości ustawionej lokalnie, zasób dynamiczny lub powiązanie nie zostaną przywrócone. W rzeczywistości, jeśli wywołasz ClearValue właściwość, która ma zasób dynamiczny lub powiązanie (bez wartości lokalnej literału), są one również czyszczone przez ClearValue wywołanie.

SetCurrentValue

Metoda SetCurrentValue jest innym sposobem ustawiania właściwości, ale nie jest w kolejności pierwszeństwa. SetCurrentValue Zamiast tego umożliwia zmianę wartości właściwości bez zastępowania źródła poprzedniej wartości. Możesz użyć SetCurrentValue dowolnego momentu, w którym chcesz ustawić wartość bez podawania tej wartości pierwszeństwa wartości lokalnej. Jeśli na przykład właściwość jest ustawiana przez wyzwalacz, a następnie przypisano inną wartość za pośrednictwem SetCurrentValuemetody , system właściwości nadal szanuje wyzwalacz, a właściwość zmieni się, jeśli wystąpi akcja wyzwalacza. SetCurrentValue umożliwia zmianę wartości właściwości bez podawania jej źródła o wyższym prioryence. Podobnie można użyć SetCurrentValue metody , aby zmienić wartość właściwości bez zastępowania powiązania.

Przymus, animacje i wartość podstawowa

Przymus i animacja działają zarówno na wartość, która jest określana jako "wartość podstawowa" w tym zestawie SDK. W związku z tym wartość podstawowa jest określana przez ocenę w górę w elementach do momentu osiągnięcia wartości 2.

W przypadku animacji wartość podstawowa może mieć wpływ na animowaną wartość, jeśli ta animacja nie określa wartości "Od" i "Do" dla niektórych zachowań, lub jeśli animacja celowo przywraca wartość podstawową po zakończeniu. Aby zobaczyć to w praktyce, uruchom przykład From, To i By Animation Target Values (Od, Do i Według wartości docelowych animacji). Spróbuj ustawić lokalne wartości wysokości prostokąta w przykładzie, tak aby początkowa wartość lokalna różniła się od dowolnej wartości "Od" w animacji. Zwróć uwagę, że animacje zaczynają się od razu przy użyciu wartości "Od" i zamieniają wartość podstawową po uruchomieniu. Animacja może określić, aby powrócić do wartości znalezionej przed animacją po jej zakończeniu, określając zatrzymanie FillBehavior. Następnie pierwszeństwo normalne jest używane do określania wartości bazowej.

Do jednej właściwości można zastosować wiele animacji, a każda z tych animacji prawdopodobnie została zdefiniowana z różnych punktów pierwszeństwa wartości. Jednak te animacje mogą potencjalnie składać swoje wartości, a nie tylko stosować animację z wyższego pierwszeństwa. Zależy to od dokładnego sposobu definiowania animacji oraz typu animowanej wartości. Aby uzyskać więcej informacji na temat animowania właściwości, zobacz Omówienie animacji.

Przymus stosuje się na najwyższym poziomie wszystkich. Nawet już uruchomiona animacja podlega przymusowi wartości. Niektóre istniejące właściwości zależności w WPF mają wbudowane przymus. W przypadku niestandardowej właściwości zależności definiujesz zachowanie wymuszania dla niestandardowej właściwości zależności, zapisując CoerceValueCallback i przekazując wywołanie zwrotne w ramach metadanych podczas tworzenia właściwości. Można również zastąpić zachowanie coercion istniejących właściwości, przesłaniając metadane 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, ponieważ te ograniczenia istnieją w tym czasie, ale wartość podstawowa jest nadal zachowywana. W związku z tym, jeśli ograniczenia przymusu zostaną później zniesione, przymus zwróci najbliższą wartość możliwą do tej wartości bazowej, a potencjalnie wpływ przymusu na właściwość przestanie obowiązywać tak szybko, jak wszystkie ograniczenia zostaną zniesione. Aby uzyskać więcej informacji na temat zachowania przymusu, zobacz Wywołania zwrotne właściwości zależności i walidacja.

Zachowania wyzwalacza

Kontrolki często definiują zachowania wyzwalacza w ramach ich domyślnego stylu w motywach. Ustawienie właściwości lokalnych kontrolek może uniemożliwić wyzwalaczom reagowanie na zdarzenia sterowane przez użytkownika wizualnie lub behawioralnie. Najczęstszym zastosowaniem wyzwalacza właściwości jest sterowanie lub właściwości stanu, takie jak IsSelected. Na przykład gdy element Button jest wyłączony (wyzwalacz dla IsEnabled elementu to false) Foreground wartość w stylu motywu jest tym, co powoduje, że kontrolka będzie wyświetlana jako "wyszarana". Jeśli jednak ustawiono wartość lokalną Foreground , normalny kolor wyszarania zostanie unieważniony przed ustawieniem właściwości lokalnych, nawet w tym scenariuszu wyzwalanym przez właściwość. Należy zachować ostrożność podczas ustawiania wartości właściwości, które mają zachowania wyzwalacza na poziomie motywu, i upewnij się, że nie zakłócasz działania zamierzonego środowiska użytkownika dla tej kontrolki.

ClearValue i pierwszeństwo wartości

Metoda ClearValue zapewnia celowe środki w celu wyczyszczenia dowolnej lokalnie zastosowanej wartości z właściwości zależności, która jest ustawiona na element. Jednak wywołanie ClearValue nie jest gwarancją, że wartość domyślna określona w metadanych podczas rejestracji właściwości jest nową obowiązującą wartością. Wszyscy inni uczestnicy pierwszeństwa wartości są nadal aktywni. Tylko lokalnie ustawiona wartość została usunięta z sekwencji pierwszeństwa. Jeśli na przykład wywołasz ClearValue właściwość, w której ta właściwość jest również ustawiana przez styl motywu, wartość motywu jest stosowana jako nowa wartość, a nie wartość domyślna oparta na metadanych. Jeśli chcesz wyrejestrować wszystkich uczestników wartości właściwości z procesu i ustawić wartość domyślną zarejestrowanych metadanych, możesz uzyskać wartość domyślną ostatecznie, wykonując zapytanie dotyczące metadanych właściwości zależności, a następnie możesz użyć wartości domyślnej, aby lokalnie ustawić właściwość za pomocą wywołania metody SetValue.

Zobacz też