Drzewa w WPF

W wielu technologiach elementy i składniki są zorganizowane w strukturze drzewa, w której deweloperzy bezpośrednio manipulują węzłami obiektów w drzewie, aby wpływać na renderowanie lub zachowanie aplikacji. Windows Presentation Foundation (WPF) Używa również kilku metafor struktury drzewa do definiowania relacji między elementami programu. W większości przypadków deweloperzy WPF mogą tworzyć aplikację w kodzie lub definiować jej części w języku XAML, myśląc koncepcyjnie o metaforze drzewa obiektów, ale będą w tym celu wywoływania określonego interfejsu API lub używania określonych znaczników zamiast niektórych ogólnych interfejsów API manipulowania drzewem obiektów, których można użyć w modelu XML DOM. WPF uwidacznia dwie klasy pomocników, które zapewniają widok metafor drzewa i LogicalTreeHelper VisualTreeHelper . Terminy drzewo wizualne i drzewo logiczne są również używane w dokumentacji WPF, ponieważ te same drzewa są przydatne do zrozumienia zachowania niektórych kluczowych funkcji WPF. W tym temacie opisano, co reprezentuje drzewo wizualne i drzewo logiczne, omówiono, w jaki sposób takie drzewa odnoszą się do ogólnej koncepcji drzewa obiektów oraz wprowadzono LogicalTreeHelper elementy i VisualTreeHelper .

Drzewa w WPF

Najbardziej kompletną strukturą drzewa WPF w programie jest drzewo obiektów. Jeśli zdefiniujesz stronę aplikacji w programie , a następnie załadujesz element , struktura drzewa zostanie utworzona na podstawie zagnieżdżonych relacji XAML XAML elementów w znacznikach. Jeśli definiujesz aplikację lub część aplikacji w kodzie, struktura drzewa jest tworzona na podstawie sposobu przypisywania wartości właściwości dla właściwości, które implementują model zawartości dla danego obiektu. W programie istnieją dwa sposoby konceptualizacji kompletnego drzewa obiektów, które można zgłaszać do publicznego interfejsu API: jako drzewo logiczne i jako Windows Presentation Foundation (WPF) drzewo wizualne. Różnice między drzewem logicznym i drzewem wizualnym nie zawsze są istotne, ale czasami mogą powodować problemy z określonymi podsystemami i wpływać na wybory w znacznikach WPF lub kodzie.

Mimo że nie zawsze manipulujesz bezpośrednio drzewem logicznym lub drzewem wizualnym, zrozumienie koncepcji interakcji drzew jest przydatne do zrozumienia WPF jako technologii. Myślenie o WPF jako metaforze drzewa ma również kluczowe znaczenie dla zrozumienia sposobu działania dziedziczenia właściwości i routingu zdarzeń w programie WPF .

Uwaga

Ponieważ drzewo obiektów jest bardziej pojęciem niż rzeczywistym interfejsem API, innym sposobem, aby myśleć o koncepcji, jest wykres obiektów. W praktyce istnieją relacje między obiektami w czasie działania, w których metafora drzewa zostanie rozbijana. Niemniej jednak, szczególnie w przypadku interfejsu użytkownika zdefiniowanego w języku XAML, metafora drzewa jest na tyle ważna, że większość dokumentacji WPF będzie używać terminu drzewo obiektów podczas odwoływania się do tej ogólnej koncepcji.

Drzewo logiczne

W WPF pliku zawartość jest dodawania do elementów interfejsu użytkownika przez ustawienie właściwości obiektów, które kopią zapasową tych elementów. Na przykład można dodać elementy do ListBox kontrolki, manipulując jej Items właściwością. W ten sposób umieszczasz elementy w ItemCollection obiekcie , który jest Items wartością właściwości. Podobnie, aby dodać obiekty do DockPanel obiektu , należy manipulować jego Children wartością właściwości. W tym miejscu dodajesz obiekty do obiektu UIElementCollection . Aby uzyskać przykładowy kod, zobacz How to: Add an Element Dynamicly(Jak dodać element dynamicznie).

W pliku umieszcza się elementy listy w kontrolce lub lub innych elementach interfejsu użytkownika w pliku , można również użyć właściwości i , jawnie lub niejawnie, jak w Extensible Application Markup Language (XAML) ListBox poniższym DockPanel Items Children przykładzie.

<DockPanel
  Name="ParentElement"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <!--implicit: <DockPanel.Children>-->
  <ListBox DockPanel.Dock="Top">
    <!--implicit: <ListBox.Items>-->
    <ListBoxItem>
      <TextBlock>Dog</TextBlock>
    </ListBoxItem>
    <ListBoxItem>
      <TextBlock>Cat</TextBlock>
    </ListBoxItem>
    <ListBoxItem>
      <TextBlock>Fish</TextBlock>
    </ListBoxItem>
  <!--implicit: </ListBox.Items>-->
  </ListBox>
  <Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>
  <!--implicit: </DockPanel.Children>-->
</DockPanel>

Gdyby ten kod XAML był przetwarzany jako kod XML w modelu obiektu dokumentu, a tagi były oznaczane jako niejawne (co byłoby prawne), wynikowe drzewo XML DOM zawierałoby elementy elementu i inne niejawne <ListBox.Items> elementy. Jednak kod XAML nie przetwarza w ten sposób odczytu znaczników i zapisu w obiektach, wynikowy wykres obiektów nie zawiera literała ListBox.Items . Ma jednak właściwość o nazwie , która zawiera , i która ListBox Items jest ItemCollection ItemCollection zainicjowana, ale pusta podczas ListBox przetwarzania kodu XAML. Następnie każdy element obiektu podrzędnego, który istnieje jako zawartość elementu , jest dodawany do obiektu ListBox ItemCollection przez wywołania parsera do ItemCollection.Add elementu . Ten przykład przetwarzania kodu XAML w drzewie obiektów jest do tej pory pozornie przykładem, w którym utworzone drzewo obiektów jest po prostu drzewem logicznym.

Drzewo logiczne nie jest jednak całym grafem obiektu, który istnieje dla interfejsu użytkownika aplikacji w czasie działania, nawet przy wywłaszniach niejawnych elementów składni JĘZYKA XAML. Głównym powodem są wizualizacje i szablony. Rozważmy na przykład Button . Drzewo logiczne zgłasza obiekt Button i jego ciąg Content . Jednak ten przycisk w drzewie obiektów czasu uruchamiania zawiera więcej informacji. W szczególności przycisk pojawia się na ekranie tylko tak, jak robi to, ponieważ zastosowano określony Button szablon kontrolki. Wizualizacje, które pochodzą z zastosowanego szablonu (na przykład zdefiniowane przez szablon ciemnoszary wokół przycisku wizualizacji) nie są zgłaszane w drzewie logicznym, nawet jeśli patrzysz na drzewo logiczne w czasie uruchamiania (np. obsługa zdarzenia wejściowego z widocznego interfejsu użytkownika, a następnie odczytywanie drzewa Border logicznego). Aby znaleźć wizualizacje szablonów, zamiast tego należy zbadać drzewo wizualizacji.

Aby uzyskać więcej informacji na temat sposobu mapowania składni na utworzony wykres obiektów i niejawnej składni w języku XAML, zobacz Składnia XAML w szczegółach lub XAML XAML w WPF .

Przeznaczenie drzewa logicznego

Drzewo logiczne istnieje, dzięki czemu modele zawartości mogą łatwo iterować po możliwych obiektach podrzędnych i dzięki czemu modele zawartości mogą być rozszerzalne. Ponadto drzewo logiczne zapewnia platformę dla niektórych powiadomień, takich jak załadowanie wszystkich obiektów w drzewie logicznym. Zasadniczo drzewo logiczne jest przybliżeniem wykresu obiektu czasu wykonywania na poziomie struktury, który wyklucza wizualizacje, ale jest odpowiednie dla wielu operacji wykonywania zapytań względem kompozycji własnej aplikacji w czasie wykonywania.

Ponadto statyczne i dynamiczne odwołania do zasobów są rozpoznawane przez sprawdzenie w górę drzewa logicznego dla kolekcji początkowego obiektu żądającego, a następnie kontynuowanie drzewa logicznego i sprawdzanie każdego (lub ) pod uwagę innej wartości zawierającej , prawdopodobnie zawierającą ten Resources FrameworkElement FrameworkContentElement Resources ResourceDictionary klucz. Drzewo logiczne jest używane do wyszukiwania zasobów, gdy jest obecne zarówno drzewo logiczne, jak i drzewo wizualne. Aby uzyskać więcej informacji na temat słowników zasobów i wyszukiwania, zobacz Zasoby XAML.

Kompozycja drzewa logicznego

Drzewo logiczne jest definiowane na poziomie platformy WPF, co oznacza, że element podstawowy WPF, który jest najbardziej odpowiedni dla operacji drzewa logicznego, to FrameworkElement lub FrameworkContentElement . Jednak jak widać, jeśli faktycznie używasz interfejsu API, drzewo logiczne czasami zawiera węzły, które nie są ani LogicalTreeHelper FrameworkElement ani FrameworkContentElement . Na przykład drzewo logiczne zgłasza Text wartość , która jest TextBlock ciągiem.

Zastępowanie drzewa logicznego

Autorzy zaawansowanych kontrolek mogą przesłonić drzewo logiczne przez zastąpienie kilku interfejsów API, które definiują sposób, w jaki ogólny obiekt lub model zawartości dodaje lub usuwa obiekty w drzewie logicznym. Aby uzyskać przykład sposobu przesłonięcia drzewa logicznego, zobacz Przesłonięcie drzewa logicznego.

Przejęcie wartości właściwości

Dziedziczenie wartości właściwości działa za pośrednictwem drzewa hybrydowego. Rzeczywiste metadane zawierające Inherits właściwość, która umożliwia dziedziczenie właściwości, to klasa na poziomie platformy FrameworkPropertyMetadata WPF. W związku z tym zarówno element nadrzędny, który przechowuje oryginalną wartość, jak i obiekt podrzędny, który dziedziczy wartość, musi mieć zarówno wartość lub , jak i muszą być częścią FrameworkElement FrameworkContentElement pewnego drzewa logicznego. Jednak w przypadku istniejących właściwości WPF, które obsługują dziedziczenie właściwości, dziedziczenie wartości właściwości może być utrwalane za pośrednictwem obiektu interweniowania, który nie znajduje się w drzewie logicznym. Dotyczy to głównie elementów szablonu, które używają wszelkich dziedziczonych wartości właściwości ustawionych dla wystąpienia, które jest szablonowane, lub nadal na wyższych poziomach kompozycji na poziomie strony, a tym samym wyższych w drzewie logicznym. Aby dziedziczenie wartości właściwości działało spójnie w obrębie takiej granicy, dziedzicząca właściwość musi być zarejestrowana jako dołączona właściwość i należy postępować zgodnie z tym wzorcem, jeśli zamierzasz zdefiniować niestandardową właściwość zależności z zachowaniem dziedziczenia właściwości. Dokładne drzewo używane do dziedziczenia właściwości nie może być całkowicie przewidywane przez metodę narzędzia klasy pomocnika, nawet w czasie działania. Aby uzyskać więcej informacji, zobacz Dziedziczenie wartości właściwości.

Drzewo wizualne

Oprócz koncepcji drzewa logicznego istnieje również koncepcja drzewa wizualnego w programie WPF . Drzewo wizualne opisuje strukturę obiektów wizualnych reprezentowaną przez Visual klasę bazową. Podczas pisania szablonu dla kontrolki definiujesz lub ponownie definiujesz drzewo wizualne, które ma zastosowanie do tej kontrolki. Drzewo wizualne jest również interesujące dla deweloperów, którzy chcą mieć kontrolę niższego poziomu nad rysowaniem ze względu na wydajność i optymalizację. Jednym z elementów drzewa wizualnego w ramach konwencjonalnego programowania aplikacji jest to, że trasy zdarzeń dla zdarzenia trasowego głównie podróżują wzdłuż drzewa WPF wizualnego, a nie drzewa logicznego. Ta subtelność zachowania kierowanego zdarzenia może nie być natychmiast widoczna, chyba że jesteś autorem kontrolki. Routing zdarzeń za pośrednictwem drzewa wizualnego umożliwia kontrolkom, które implementują kompozycję na poziomie wizualizacji w celu obsługi zdarzeń lub tworzenia elementów ustawiających zdarzenia.

Drzewa, elementy zawartości i hosty zawartości

Elementy zawartości (klasy, które pochodzą od klasy ) nie są częścią drzewa wizualnego; nie dziedziczą i nie ContentElement Visual mają reprezentacji wizualnej. Aby w ogóle pojawiać się w interfejsie użytkownika, musi być hostowany na hoście zawartości, który jest zarówno uczestnikiem drzewa ContentElement Visual logicznego, jak i uczestnikiem drzewa logicznego. Zazwyczaj takim obiektem jest FrameworkElement . Można określić, że host zawartości jest nieco jak "przeglądarka" zawartości i wybiera sposób wyświetlania tej zawartości w regionie ekranu, który kontroluje host. Gdy zawartość jest hostowana, zawartość może być uczestnikiem niektórych procesów drzewa, które są zwykle skojarzone z drzewem wizualnym. Ogólnie rzecz biorąc, klasa hosta zawiera kod implementacji, który dodaje hostowane elementy do trasy zdarzeń za pośrednictwem podwęzła drzewa logicznego zawartości, mimo że hostowana zawartość nie jest częścią FrameworkElement ContentElement prawdziwego drzewa wizualnego. Jest to niezbędne, aby element może ContentElement pozysać trasowane zdarzenie, które kieruje do dowolnego elementu innego niż sam.

Przechodzenie drzewa

Klasa LogicalTreeHelper udostępnia metody , i dla GetChildren GetParent FindLogicalNode przechodzenia przez drzewo logiczne. W większości przypadków nie należy przechodzić przez drzewo logiczne istniejących kontrolek, ponieważ te kontrolki prawie zawsze uwidoczniają ich logiczne elementy podrzędne jako dedykowaną właściwość kolekcji, która obsługuje dostęp do kolekcji, taką jak , indeksator i Add tak dalej. Przechodzenie drzewa jest głównie scenariuszem używanym przez autorów kontrolek, którzy nie zdecydowali się na wyprowadzenie z zamierzonych wzorców kontrolek, takich jak lub gdzie właściwości kolekcji są już zdefiniowane, i którzy mają zapewnić obsługę własnych właściwości ItemsControl Panel kolekcji.

Drzewo wizualne obsługuje również klasę pomocnika dla przechodzenia przez drzewo wizualne, VisualTreeHelper . Drzewo wizualne nie jest udostępniane tak wygodnie za pośrednictwem właściwości specyficznych dla kontrolki, więc klasa jest zalecanym sposobem przechodzenia przez drzewo wizualne, jeśli jest to konieczne w VisualTreeHelper scenariuszu programowania. Aby uzyskać więcej informacji, zobacz WPF Graphics Rendering Overview (Omówienie renderowania grafiki WPF).

Uwaga

Czasami konieczne jest zbadanie drzewa wizualnego zastosowanego szablonu. Należy zachować ostrożność podczas korzystania z tej techniki. Nawet w przypadku przechodzenia przez drzewo wizualne dla kontrolki, w której definiujesz szablon, użytkownicy kontrolki mogą zawsze zmienić szablon, ustawiając właściwość dla wystąpień, a nawet użytkownik końcowy może wpływać na zastosowany szablon, zmieniając Template motyw systemowy.

Trasy dla zdarzeń trasowane jako "drzewo"

Jak wspomniano wcześniej, trasa dowolnego przekierowywnego zdarzenia jest przekierowyowana przez pojedynczą i wstępnie określoną ścieżkę drzewa, która jest hybrydą reprezentacji drzewa wizualnego i logicznego. Trasa zdarzenia może odbywać się w górę lub w dół w obrębie drzewa w zależności od tego, czy jest to zdarzenie tunelowania, czy podsuwu. Koncepcja trasy zdarzeń nie ma bezpośrednio obsługi klasy pomocnika, która może służyć do "chodu" trasy zdarzeń niezależnie od wystąpienia zdarzenia, które faktycznie kieruje. Istnieje klasa, która reprezentuje trasę , ale metody tej klasy są EventRoute zwykle tylko do użytku wewnętrznego.

Słowniki zasobów i drzewa

Odnośnik do słownika zasobów dla wszystkich zdefiniowanych na stronie przechodzi zasadniczo Resources przez drzewo logiczne. Obiekty, które nie znajdują się w drzewie logicznym, mogą odwoływać się do zasobów z kluczami, ale sekwencja wyszukiwania zasobów rozpoczyna się od punktu, w którym ten obiekt jest połączony z drzewem logicznym. W WPF tylko węzły drzewa logicznego mogą mieć właściwość zawierającą element , dlatego przechodzenie przez drzewo wizualne w celu szukania zasobów z kluczami z obiektu nie ma żadnej Resources ResourceDictionary ResourceDictionary korzyści.

Jednak wyszukiwania zasobów może również wykraczać poza natychmiastowe drzewo logiczne. W przypadku znaczników aplikacji odnośniki zasobów mogą następnie przejść do słowników zasobów na poziomie aplikacji, a następnie do obsługi motywów i wartości systemowych, które są przywołyne jako statyczne właściwości lub klucze. Motywy mogą również odwoływać się do wartości systemowych poza drzewem logicznym motywu, jeśli odwołania do zasobów są dynamiczne. Aby uzyskać więcej informacji na temat słowników zasobów i logiki wyszukiwania, zobacz Zasoby XAML.

Zobacz też