Bomen in WPF
In veel technologieën worden elementen en onderdelen ingedeeld in een structuurstructuur waar ontwikkelaars de objectknooppunten in de structuur rechtstreeks manipuleren om de weergave of het gedrag van een toepassing te beïnvloeden. Windows Presentation Foundation (WPF) maakt ook gebruik van verschillende boomstructuurmetaforen om relaties tussen programma-elementen te definiëren. WpF-ontwikkelaars kunnen voor het grootste deel een toepassing maken in code of delen van de toepassing definiëren in XAML terwijl ze conceptueel denken aan de objectstructuurafoor, maar specifieke API aanroepen of specifieke markeringen gebruiken om dit te doen in plaats van een algemene API voor objectstructuurbewerking, zoals u in XML DOM kunt gebruiken. WPF maakt twee helperklassen beschikbaar die een boomstructuur-metafoor bieden, LogicalTreeHelper en VisualTreeHelper. De termen visuele structuur en logische structuur worden ook gebruikt in de WPF-documentatie, omdat dezelfde bomen handig zijn voor het begrijpen van het gedrag van bepaalde belangrijke WPF-functies. In dit onderwerp wordt gedefinieerd wat de visuele boomstructuur en logische structuur vertegenwoordigen, wordt besproken hoe dergelijke bomen zich verhouden tot een algemeen objectstructuurconcept en worden LogicalTreeHelper en VisualTreeHelper's geïntroduceerd.
Bomen in WPF
De meest complete boomstructuur in WPF is de objectboom. Als u een applicatiepagina in XAML definieert en vervolgens de XAML laadt, wordt de structuur gemaakt op basis van de geneste relaties van de elementen in de opmaaktaal. Als u een toepassing of een deel van de toepassing in code definieert, wordt de structuurstructuur gemaakt op basis van hoe u eigenschapswaarden toewijst voor eigenschappen die het inhoudsmodel voor een bepaald object implementeren. In WPF zijn er twee manieren waarop de volledige objectstructuur wordt geconceptualiseerd en kan worden gerapporteerd aan de openbare API: als de logische structuur en als de visualstructuur. Het onderscheid tussen logische structuur en visuele structuur is niet altijd belangrijk, maar ze kunnen af en toe problemen veroorzaken met bepaalde WPF-subsystemen en invloed hebben op keuzes die u maakt in markeringen of code.
Hoewel u niet altijd de logische structuur of de visuele structuur rechtstreeks bewerkt, is het begrijpen van de concepten van hoe de bomen communiceren nuttig voor het begrijpen van WPF als technologie. Het is van cruciaal belang om WPF als een soort boommetafoor te beschouwen om te begrijpen hoe eigenschappenovererving en gebeurtenisroutering in WPF werken.
Notitie
Omdat de objectstructuur meer van een concept is dan een werkelijke API, is een andere manier om het concept te beschouwen als een objectgrafiek. In de praktijk zijn er relaties tussen objecten tijdens runtime waarbij de metafoor van de boom afbreekt. In het bijzonder met de door XAML gedefinieerde gebruikersinterface is de metafoor van de structuur echter relevant genoeg dat de meeste WPF-documentatie de term objectstructuur gebruikt bij het verwijzen naar dit algemene concept.
De logische structuur
In WPF voegt u inhoud toe aan UI-elementen door de eigenschappen van de objecten die deze elementen ondersteunen in te stellen. U voegt bijvoorbeeld items toe aan een ListBox besturingselement door de eigenschap Items te bewerken. Als u dit doet, plaatst u items in de ItemCollection die de eigenschapswaarde Items is. Als u objecten aan een DockPanelwilt toevoegen, bewerkt u de bijbehorende Children eigenschapswaarde. Hier voegt u objecten toe aan de UIElementCollection. Zie Procedure voor een codevoorbeeld: Een element dynamischtoevoegen.
Wanneer u in Extensible Application Markup Language (XAML) lijstitems in een ListBox of besturingselementen of andere UI-elementen in een DockPanelplaatst, gebruikt u ook de eigenschappen Items en Children, expliciet of impliciet, zoals in het volgende voorbeeld.
<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>
Als u deze XAML als XML onder een documentobjectmodel zou verwerken en als u de tags als impliciet had opgenomen (wat legaal zou zijn), zou de resulterende XML DOM-structuur elementen bevatten voor <ListBox.Items>
en de andere impliciete items. Maar XAML verwerkt het niet op die manier; wanneer u de opmaak leest en naar objecten schrijft, bevat de resulterende objectgrafiek niet letterlijk ListBox.Items
. Het heeft echter wel een eigenschap ListBox met de naam Items
die een ItemCollectionbevat en dat ItemCollection wordt geïnitialiseerd, maar leeg is wanneer de ListBox XAML wordt verwerkt. Vervolgens wordt elk kindobjectelement dat als inhoud voorkomt voor de ListBox toegevoegd aan de ItemCollection door parser-aanroepen naar ItemCollection.Add
. Dit voorbeeld van het verwerken van XAML in een objectstructuur is tot nu toe een voorbeeld waarin de gemaakte objectstructuur in feite de logische structuur is.
De logische structuur is echter niet de volledige objectgrafiek die bestaat voor de gebruikersinterface van uw toepassing tijdens runtime, zelfs niet als de impliciete syntaxisitems van XAML zijn meegelicht. De belangrijkste reden hiervoor zijn visuals en sjablonen. Denk bijvoorbeeld aan de Button. De logische boom rapporteert het Button object en ook de tekenreeks Content
. Maar er is meer aan deze knop in de runtime-objectstructuur. De knop verschijnt op het scherm zoals hij doet, alleen doordat er een specifieke Button besturingssjabloon is toegepast. De visuals die afkomstig zijn van een toegepaste sjabloon (zoals de door de sjabloon gedefinieerde Border van donkergrijs rond de visualknop) worden niet gerapporteerd in de logische structuur, zelfs als u tijdens de runtime naar de logische structuur kijkt (zoals het verwerken van een invoergebeurtenis vanuit de zichtbare gebruikersinterface en vervolgens de logische structuur leest). Als u de sjabloonvisuals wilt vinden, moet u in plaats daarvan de visualstructuur onderzoeken.
Zie XAML-syntaxis in detail of XAML in WPFvoor meer informatie over hoe XAML-syntaxis wordt omgezet naar de gegenereerde objectgraf en impliciete syntaxis in XAML.
Het doel van de logische structuur
De logische structuur bestaat zodat inhoudsmodellen gemakkelijk kunnen itereren over hun mogelijke kindobjecten en zodat inhoudsmodellen uitbreidbaar zijn. De logische structuur biedt ook een framework voor bepaalde meldingen, zoals wanneer alle objecten in de logische structuur worden geladen. In principe is de logische boom een benadering van een runtimeobjectgrafiek op frameworkniveau, die visuals uitsluit maar toch voldoende is voor veel querybewerkingen tegen de samenstelling van uw eigen runtime-applicatie.
Bovendien worden zowel statische als dynamische bronverwijzingen opgelost door omhoog te zoeken in de logische structuur voor Resources verzamelingen op het eerste aanvraagobject, en vervolgens door te gaan met de logische structuur en elke FrameworkElement (of FrameworkContentElement) te controleren op een andere Resources
waarde die een ResourceDictionarybevat, mogelijk die die sleutel bevat. De logische boomstructuur wordt gebruikt voor het opzoeken van resources wanneer zowel de logische boomstructuur als de visuele boomstructuur aanwezig zijn. Zie XAML-resourcesvoor meer informatie over resourcewoordenlijsten en opzoekacties.
Samenstelling van de logische boom
De logische structuur wordt gedefinieerd op het niveau van het WPF-framework, wat betekent dat het WPF-basiselement dat het meest relevant is voor logische structuurbewerkingen, FrameworkElement of FrameworkContentElementis. Zoals u echter kunt zien of u de LogicalTreeHelper-API daadwerkelijk gebruikt, bevat de logische structuur soms knooppunten die niet FrameworkElement of FrameworkContentElementzijn. De logische structuur rapporteert bijvoorbeeld de Text waarde van een TextBlock, een tekenreeks.
De logische structuur overschrijven
Auteurs van geavanceerde besturingselementen kunnen de logische structuur overschrijven door verschillende API's te overschrijven die bepalen hoe een algemeen object of inhoudsmodel objecten toevoegt of verwijdert in de logische structuur. Zie De logische structuur overschrijvenvoor een voorbeeld van het overschrijven van de logische structuur.
Overname van eigenschapswaarde
Overname van eigenschapswaarden werkt via een hybride boom. De werkelijke metagegevens die de Inherits eigenschap bevatten waarmee overname van eigenschappen mogelijk is, is de WPF-frameworkniveau FrameworkPropertyMetadata klasse. Daarom moeten zowel het ouderobject met de oorspronkelijke waarde als het kinderobject dat deze waarde overneemt, beide FrameworkElement of FrameworkContentElementzijn, en moeten ze beide deel uitmaken van een of andere logische structuur. Voor bestaande WPF-eigenschappen die eigenschapsovername ondersteunen, kan de overname van eigenschapswaarden echter blijven bestaan via een tussenliggend object dat zich niet in de logische structuur bevindt. Dit is voornamelijk relevant voor het gebruik van sjabloonelementen, waarbij overgenomen eigenschapswaarden worden gebruikt die zijn ingesteld op het exemplaar dat is gesjabloond, of op nog hogere niveaus van samenstelling op paginaniveau en dus hoger in de logische structuur. Als u wilt dat overname van eigenschapswaarden consistent over een dergelijke grens werkt, moet de overnemende eigenschap worden geregistreerd als een gekoppelde eigenschap en moet u dit patroon volgen als u een aangepaste afhankelijkheidseigenschap wilt definiëren met eigenschapsovernamegedrag. De exacte structuur die wordt gebruikt voor overname van eigenschappen kan niet volledig worden verwacht door een helperklassehulpprogrammamethode, zelfs tijdens runtime. Zie overname van eigenschapswaardenvoor meer informatie.
De visualstructuur
Naast het concept van de logische structuur is er ook het concept van de visuele structuur in WPF. In de visuele boom wordt de structuur van visuele objecten beschreven, zoals weergegeven door de Visual-basisklasse. Wanneer u een sjabloon voor een besturingselement schrijft, definieert u de visuele structuur die van toepassing is op dat besturingselement. De visuele structuur is ook interessant voor ontwikkelaars die om prestatie- en optimalisatieredenen controle willen over tekenen op lager niveau. Een weergave van de visualstructuur in conventionele WPF-toepassingsprogrammering is dat routes voor een gerouteerde gebeurtenis meestal langs de visuele boomstructuur verlopen, niet de logische structuur. Deze subtiliteit van het gedrag van gerouteerde gebeurtenissen is mogelijk niet onmiddellijk zichtbaar, tenzij u een auteur van een besturingselement bent. Door gebeurtenissen via de visuele boom te routeren, kunnen besturingselementen die compositie op visueel niveau implementeren, gebeurtenissen verwerken of gebeurtenissetters maken.
Bomen, inhoudselementen en inhoudhosts
Inhoudselementen (klassen die zijn afgeleid van ContentElement) maken geen deel uit van de visuele structuur; ze nemen niet over van Visual en hebben geen visuele weergave. Om in een gebruikersinterface te verschijnen, moet een ContentElement worden gehost in een host die zowel een Visual is als deelneemt aan een logische boom. Meestal is een dergelijk object een FrameworkElement. U kunt zich voorstellen dat de inhoudshost enigszins is als een 'browser' voor de inhoud en kiest hoe die inhoud weergegeven wordt in de gebieden van het scherm die het beheert. Wanneer de inhoud wordt gehost, kan de inhoud deelnemen aan bepaalde processen in de boomstructuur die normaal gesproken aan de visuele structuur zijn gekoppeld. Over het algemeen bevat de FrameworkElement-hostklasse implementatiecode die ervoor zorgt dat gehoste ContentElement's worden toegevoegd aan de gebeurtenisroute via subknooppunten van de logische structuur van de inhoud, ook al maakt de gehoste inhoud geen deel uit van de echte visuals. Dit is nodig zodat een ContentElement een gerouteerde gebeurtenis kan maken die naar een ander element dan zichzelf routeert.
Boomdoorkruising
De klasse LogicalTreeHelper biedt de GetChildren, GetParenten FindLogicalNode methoden voor het doorkruisen van logische structuren. In de meeste gevallen hoeft u de logische structuur van bestaande besturingselementen niet te doorlopen, omdat deze besturingselementen bijna altijd hun logische onderliggende elementen beschikbaar maken als een toegewezen verzamelingseigenschap die toegang tot verzamelingen ondersteunt, zoals Add
, een indexeerfunctie, enzovoort. Tree traversal is voornamelijk een scenario dat wordt gebruikt door auteurs van besturingselementen die ervoor kiezen om niet af te leiden van beoogde controlepatronen, zoals ItemsControl of Panel waar verzamelingseigenschappen al zijn gedefinieerd en die hun eigen ondersteuning voor verzamelingseigenschappen willen bieden.
De visuele boom ondersteunt ook een helperklasse voor het navigeren door de visuele boom, VisualTreeHelper. De visualstructuur wordt niet zo handig weergegeven via besturingsspecifieke eigenschappen, dus de VisualTreeHelper klasse is de aanbevolen manier om de visualstructuur te doorlopen als dat nodig is voor uw programmeerscenario. Zie WPF Graphics Rendering Overviewvoor meer informatie.
Notitie
Soms is het nodig om de visuele structuur van een toegepaste sjabloon te onderzoeken. Wees voorzichtig bij het gebruik van deze techniek. Zelfs als u een visuele structuur doorkruist voor een besturingselement waarin u de sjabloon definieert, kunnen gebruikers van uw besturingselement de sjabloon altijd wijzigen door de eigenschap Template in te stellen op exemplaren, en zelfs de eindgebruiker kan de toegepaste sjabloon beïnvloeden door het systeemthema te wijzigen.
Routes voor gerouteerde gebeurtenissen als een 'boomstructuur'
Zoals eerder vermeld, loopt de route van een opgegeven gerouteerde gebeurtenis langs één en vooraf bepaald pad van een boom die een hybride weergave is van de visuele en logische structuur. De gebeurtenisroute kan in de richting omhoog of omlaag in de boomstructuur worden geleid, afhankelijk van of het een tunneling- of bubblinggerouteerde gebeurtenis is. Het concept van de gebeurtenisroute heeft geen rechtstreeks ondersteunende helperklasse die kan worden gebruikt om door de gebeurtenisroute te navigeren zonder een gebeurtenis te hoeven genereren die echt wordt gerouteerd. Er is een klasse die de route vertegenwoordigt, EventRoute, maar de methoden van die klasse zijn over het algemeen alleen voor intern gebruik.
Resourcewoordenlijsten en bomen
Zoeken in resourcewoordenlijst voor alle Resources
die zijn gedefinieerd op een pagina, doorkruist in feite de logische structuur. Objecten die zich niet in de logische structuur bevinden, kunnen verwijzen naar sleutelresources, maar de opzoekvolgorde van resources begint op het punt waarop dat object is verbonden met de logische structuur. In WPF kunnen alleen logische boomknooppunten een Resources
eigenschap hebben die een ResourceDictionarybevat, waardoor er geen voordeel is om de visuele boom te doorlopen die op zoek is naar sleutelbronnen van een ResourceDictionary.
Het opzoeken van resources kan echter ook verder gaan dan de onmiddellijke logische structuur. Voor toepassingsmarkeringen kan de resourcezoekactie vervolgens doorgaan naar resourcewoordenlijsten op toepassingsniveau en vervolgens naar ondersteuning van thema's en systeemwaarden waarnaar wordt verwezen als statische eigenschappen of sleutels. Thema's zelf kunnen ook verwijzen naar systeemwaarden buiten de logische structuur van het thema als de bronverwijzingen dynamisch zijn. Zie XAML-resourcesvoor meer informatie over resourcewoordenlijsten en de opzoeklogica.
Zie ook
.NET Desktop feedback