Stromy v subsystému WPF

V mnoha technologiích jsou prvky a komponenty uspořádány ve stromové struktuře, kde vývojáři přímo manipulují s uzly objektů ve stromu, aby ovlivnili vykreslování nebo chování aplikace. Windows Presentation Foundation (WPF) také používá několik metafor struktury stromové struktury k definování vztahů mezi prvky programu. Pro většinu vývojářů WPF mohou vytvořit aplikaci v kódu nebo definovat části aplikace v XAML a současně přemýšlet koncepčně o metaforu stromu objektů, ale budou volat konkrétní rozhraní API nebo použít konkrétní značky, aby to udělali místo některé obecné rozhraní API pro manipulaci se stromem objektů, jako je použití v JAZYCE XML DOM. WPF zveřejňuje dvě pomocné třídy, které poskytují zobrazení LogicalTreeHelper metafory stromu a VisualTreeHelper. Termíny vizuální strom a logický strom se také používají v dokumentaci WPF, protože tyto stejné stromy jsou užitečné pro pochopení chování určitých klíčových funkcí WPF. Toto téma definuje, co vizuální strom a logický strom představují, popisuje, jak tyto stromy souvisejí s celkovým konceptem stromu objektů, a představuje LogicalTreeHelper a VisualTreeHelpers.

Stromy v subsystému WPF

Nejúplnější stromovou strukturou ve WPF je strom objektů. Pokud definujete stránku aplikace v JAZYCE XAML a pak načtete XAML, stromová struktura se vytvoří na základě relací vnořování prvků v revizí. Pokud definujete aplikaci nebo část aplikace v kódu, vytvoří se stromová struktura na základě toho, jak přiřadíte hodnoty vlastností pro vlastnosti, které implementují kon režim stanu l pro daný objekt. Ve WPF existují dva způsoby, jak je kompletní strom objektů koncepční a lze ho hlásit do svého veřejného rozhraní API: jako logický strom a jako vizuální strom. Rozdíly mezi logickým stromem a vizuálním stromem nemusí být vždy důležité, ale někdy můžou způsobit problémy s určitými subsystémy WPF a ovlivnit volby, které uděláte v kódu nebo kódu.

I když s logickým stromem nebo stromem vizuálu nemusíte vždy manipulovat přímo, pochopení konceptů interakce stromů je užitečné pro pochopení WPF jako technologie. Myšlení WPF jako stromové metafory určitého druhu je také zásadní pro pochopení fungování dědičnosti vlastností a směrování událostí ve WPF.

Poznámka:

Protože strom objektů je spíše koncept než skutečné rozhraní API, dalším způsobem, jak si představit koncept, je jako objektový graf. V praxi existují vztahy mezi objekty za běhu, kde se metafora stromu rozdělí. Metafora stromu je však relevantní zejména u uživatelského rozhraní definovaného JAZYKem XAML, aby většina dokumentace WPF při odkazování na tento obecný koncept používala strom objektů termínů.

Logický strom

Ve WPF přidáte obsah do prvků uživatelského rozhraní nastavením vlastností objektů, které tyto prvky zpět. Například přidáte položky do ListBox ovládacího prvku manipulací s jeho Items vlastností. Uděláte to tak, že Items položky umístíte do ItemCollection hodnoty vlastnosti. Podobně, chcete-li přidat objekty do objektu DockPanel, budete manipulovat s jeho Children hodnotou vlastnosti. Zde přidáváte objekty do objektu UIElementCollection. Příklad kódu naleznete v tématu Postupy: Přidání elementu dynamicky.

V jazyku XAML (Extensible Application Markup Language) při umístění položek seznamu do ListBox nebo ovládacích prvků nebo jiných prvků uživatelského rozhraní do DockPanel, použijete Items také vlastnosti Children a explicitně nebo implicitně, jako v následujícím příkladu.

<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>

Pokud byste tento KÓD XAML zpracovávali jako XML v rámci modelu objektu dokumentu a pokud jste zahrnuli značky okomentované jako implicitní (což by bylo legální), výsledný strom XML DOM by zahrnoval elementy pro <ListBox.Items> a další implicitní položky. Xaml ale tento způsob nezpracová při čtení revizí a zápisu do objektů, výsledný objektový graf neobsahuje ListBox.Itemsdoslova . Má však ListBox vlastnost s názvem Items , která obsahuje ItemCollectiona která ItemCollection je inicializována, ale prázdná při ListBox zpracování XAML. Potom každý podřízený objekt prvek, který existuje jako obsah pro objekt je ListBox přidán do ItemCollection analyzátoru volání ItemCollection.Add. Tento příklad zpracování XAML do stromu objektů je zatím zdánlivě příkladem, ve kterém je vytvořený strom objektu v podstatě logickým stromem.

Logický strom však není celý graf objektů, který existuje pro uživatelské rozhraní vaší aplikace za běhu, i když jsou zatěžovány implicitní položky syntaxe XAML. Hlavním důvodem je vizuály a šablony. Představte si Buttonnapříklad . Logický strom hlásí Button objekt a také jeho řetězec Content. Toto tlačítko je ale ve stromu objektů za běhu ještě více. Konkrétně se tlačítko zobrazuje jenom na obrazovce, jak to dělá, protože byla použita konkrétní Button šablona ovládacího prvku. Vizuály, které pocházejí z použité šablony (například šablony definované Border tmavě šedým kolem tlačítka vizuálu), nejsou v logickém stromu hlášeny, i když se během běhu díváte na logický strom (například zpracování vstupní události z viditelného uživatelského rozhraní a následné čtení logického stromu). Pokud chcete najít vizuály šablony, museli byste místo toho prozkoumat strom vizuálu.

Další informace o tom, jak se syntaxe XAML mapuje na vytvořený objekt graf a implicitní syntaxi v JAZYCE XAML, naleznete v tématu Syntaxe XAML Podrobně nebo XAML ve WPF.

Účel logického stromu

Logický stromexistujechm objektům existuje tak režim stanu, aby bylo možné snadno iterovat nad jejich možnými podřízenými objekty a aby bylo možné rozšířit režim stanu ls. Logický strom také poskytuje rozhraní pro určitá oznámení, například při načtení všech objektů v logickém stromu. Logický strom je v podstatě aproximace grafu objektu doby běhu na úrovni architektury, která vylučuje vizuály, ale je vhodná pro mnoho operací dotazování na složení vaší aplikace za běhu.

Kromě toho se statické i dynamické odkazy na prostředky přeloží tak, že se probíjí v logickém stromu Resources kolekcí na počátečním požadovaném objektu, a pak pokračuje v logickém stromu a kontroluje každou FrameworkElement (nebo FrameworkContentElement) pro jinou ResourcesResourceDictionaryhodnotu, která obsahuje klíč , případně tento klíč. Logický strom se používá pro vyhledávání prostředků, když je k dispozici logický strom i strom vizuálu. Další informace o slovníkech prostředků a vyhledávání najdete v tématu Prostředky XAML.

Složení logického stromu

Logický strom je definován na úrovni architektury WPF, což znamená, že základní prvek WPF, který je nejrelevantní pro operace logického stromu je buď FrameworkElement nebo FrameworkContentElement. Jak ale vidíte, jestli skutečně používáte LogicalTreeHelper rozhraní API, logický strom někdy obsahuje uzly, které nejsou nebo FrameworkElementFrameworkContentElement. Například logický strom hlásí Text hodnotu TextBlock, což je řetězec.

Přepsání logického stromu

Pokročilí autoři ovládacího prvku mohou přepsat logický strom přepsáním několika rozhraní API, která definují, jak obecný objekt nebo kon režim stanu l přidává nebo odebírá objekty v rámci logického stromu. Příklad přepsání logického stromu naleznete v tématu Přepsání logického stromu.

Dědičnost hodnoty vlastnosti

Dědičnost hodnot vlastností funguje prostřednictvím hybridního stromu. Skutečná metadata, která obsahují Inherits vlastnost, která umožňuje dědičnost vlastností, je WPF framework-level FrameworkPropertyMetadata třída. Proto jak nadřazený objekt, který obsahuje původní hodnotu, tak podřízený objekt, který dědí danou hodnotu musí být FrameworkElement nebo FrameworkContentElementa oba musí být součástí některého logického stromu. U existujících vlastností WPF, které podporují dědičnost vlastností, je však dědičnost hodnoty vlastnosti schopna zachovat prostřednictvím intervenujícího objektu, který není v logickém stromu. Hlavně to je důležité pro použití prvků šablony použít všechny zděděné hodnoty vlastností nastavené buď na instanci, která je šablona, nebo na stále vyšší úrovně složení na úrovni stránky, a proto vyšší v logickém stromu. Aby dědičnost hodnot vlastností fungovala konzistentně napříč takovou hranicí, musí být dědění vlastnost registrována jako připojená vlastnost a pokud chcete definovat vlastní vlastnost závislostí s chováním dědičnosti vlastností, měli byste postupovat podle tohoto vzoru. Přesný strom použitý pro dědičnost vlastností nemůže být zcela očekáván metodou pomocné třídy, a to ani za běhu. Další informace naleznete v tématu Dědičnost hodnot vlastností.

Vizuální strom

Kromě konceptu logického stromu existuje také koncept vizuálního stromu ve WPF. Vizuální strom popisuje strukturu vizuálních objektů, jak je reprezentováno Visual základní třídou. Při psaní šablony pro ovládací prvek definujete nebo znovu definujete strom vizuálu, který se vztahuje na tento ovládací prvek. Vizuální strom je také zajímavý pro vývojáře, kteří chtějí mít kontrolu nad kreslením na nižší úrovni z důvodů výkonu a optimalizace. Jednou z expozic vizuálního stromu v rámci konvenčního programování aplikací WPF je to, že trasy událostí směrované události většinou cestují podél vizuálního stromu, nikoli logický strom. Toto jemné chování směrovaných událostí nemusí být okamžitě zřejmé, pokud nejste autorem ovládacího prvku. Směrování událostí prostřednictvím vizuálního stromu umožňuje ovládací prvky, které implementují složení na úrovni vizuálu, aby zpracovávaly události nebo vytvářely settery událostí.

Stromy, prvky obsahu a hostitelé obsahu

Prvky obsahu (třídy, které jsou odvozeny ContentElement) nejsou součástí vizuálního stromu; nedědí z Visual nich a nemají vizuální reprezentaci. Aby se v uživatelském rozhraní vůbec zobrazoval, ContentElement musí být hostovaný v hostiteli obsahu, který je účastníkem Visual i logického stromu. Obvykle takový objekt je FrameworkElement. Můžete koncepčně určit, že hostitel obsahu je trochu jako prohlížeč obsahu, a zvolí, jak tento obsah zobrazit v oblasti obrazovky, kterou řídí hostitel. Když je obsah hostovaný, může být obsah účastníkem určitých procesů stromu, které jsou obvykle přidruženy ke stromu vizuálu. Obecně platí, FrameworkElement že třída hostitele obsahuje implementační kód, který přidá všechny hostované ContentElement do trasy události přes podnode logického stromu obsahu, i když hostovaný obsah není součástí skutečného vizuálního stromu. To je nezbytné, aby ContentElement mohl zdroj směrované události, která směruje na jakýkoli jiný prvek než samotný.

Procházení stromu

Třída LogicalTreeHelper poskytuje GetChildren, GetParenta FindLogicalNode metody pro procházení logického stromu. Ve většině případů byste neměli procházet logický strom existujících ovládacích prvků, protože tyto ovládací prvky téměř vždy zveřejňují jejich logické podřízené prvky jako vyhrazenou vlastnost kolekce, která podporuje přístup k kolekci, jako Addje například , indexer atd. Procházení stromem je hlavně scénář, který používají autoři ovládacích prvků, kteří se rozhodnou neodvozovat z zamýšlených vzorů ovládacích prvků, jako ItemsControl jsou nebo Panel kde jsou vlastnosti kolekce již definovány, a kteří mají v úmyslu poskytnout vlastní podporu vlastností kolekce.

Vizuální strom také podporuje pomocnou třídu pro procházení vizuálního stromu, VisualTreeHelper. Vizuální strom není přístupný tak pohodlně prostřednictvím vlastností specifických pro řízení, takže VisualTreeHelper třída je doporučený způsob, jak procházet vizuální strom, pokud je to nezbytné pro váš programovací scénář. Další informace najdete v přehledu vykreslování grafiky ve WPF.

Poznámka:

Někdy je nutné prozkoumat vizuální strom použité šablony. Při použití této techniky byste měli být opatrní. I když procházíte vizuální strom ovládacího prvku, ve kterém šablonu definujete, můžou uživatelé ovládacího prvku kdykoli změnit šablonu nastavením Template vlastnosti na instancích a dokonce i koncový uživatel může ovlivnit použitou šablonu změnou systémového motivu.

Trasy pro směrované události jako strom

Jak už bylo zmíněno dříve, trasa každé směrované události se pohybuje po jedné a předem určené cestě stromu, která je hybridním znázorněným vizuálním a logickým stromem. Trasa události může v závislosti na tom, jestli se jedná o tunelovou nebo bublinovou událost směrovanou událostí, cestovat ve stromu nahoru nebo dolů. Koncept trasy událostí nemá přímou podpůrnou třídu, která by se dala použít k "procházkě" trasy události nezávisle na vyvolání události, která ve skutečnosti směruje. Existuje třída, která představuje trasu, EventRouteale metody této třídy jsou obecně určené pouze pro interní použití.

Slovníky a stromy zdrojů

Vyhledávání ve slovníku prostředků pro všechny Resources definované na stránce prochází v podstatě logickým stromem. Objekty, které nejsou v logickém stromu, mohou odkazovat na klíčové prostředky, ale pořadí vyhledávání prostředků začíná v okamžiku, kdy je tento objekt připojen k logickému stromu. Ve WPF můžou mít Resources pouze uzly logického stromu vlastnost, která obsahuje ResourceDictionary, a proto neexistuje žádný přínos při procházení vizuálního stromu hledá klíčové prostředky z objektu ResourceDictionary.

Vyhledávání prostředků se ale může rozšířit i nad rámec bezprostředního logického stromu. U značek aplikací může vyhledávání prostředků pokračovat dál ve slovníkech prostředků na úrovni aplikace a pak podporovat motiv a systémové hodnoty, na které odkazují statické vlastnosti nebo klíče. Motivy mohou také odkazovat na systémové hodnoty mimo logický strom motivu, pokud jsou odkazy na prostředky dynamické. Další informace o slovníkech prostředků a logice vyhledávání najdete v tématu Prostředky XAML.

Viz také