Megosztás a következőn keresztül:


Fák a WPF-ben

Számos technológia esetében az elemek és összetevők egy fastruktúrában vannak rendszerezve, ahol a fejlesztők közvetlenül manipulálják a fa objektumcsomópontjait, hogy befolyásolják az alkalmazások renderelését vagy viselkedését. A Windows Presentation Foundation (WPF) több faszerkezetes metaforát is használ a programelemek közötti kapcsolatok meghatározásához. A legtöbb esetben a WPF-fejlesztők létrehozhatnak egy alkalmazást kódban, vagy meghatározhatják az alkalmazás egyes részeit az XAML-ben, miközben elméletileg az objektumfa metaforára gondolnak, de konkrét API-t hívnak meg, vagy konkrét korrektúrát használnak erre, nem pedig valamilyen általános objektumfa-kezelési API-t, például az XML DOM-ban. A WPF két segédosztályt tesz elérhetővé, LogicalTreeHelper és VisualTreeHelper, amelyek egy fára épülő nézetet biztosítanak. A vizualizációs fa és a logikai fa kifejezéseket a WPF dokumentációja is használja, mivel ezek a fák hasznosak bizonyos kulcsfontosságú WPF-funkciók viselkedésének megértéséhez. Ez a témakör meghatározza, hogy a vizualizációs fa és a logikai fa mit jelöl, ismerteti, hogyan viszonyulnak ezek a fák egy általános objektumfa-fogalomhoz, és bemutatja LogicalTreeHelper és VisualTreeHelpers.

Fák a WPF-ben

A WPF legteljesebb faszerkezete az objektumfa. Ha egy alkalmazáslapot definiál az XAML-ben, majd betölti az XAML-t, a faszerkezet a korrektúra elemeinek beágyazott kapcsolatai alapján jön létre. Ha egy alkalmazást vagy az alkalmazás egy részét kódban definiálja, akkor a faszerkezet az alapján jön létre, hogy hogyan rendel hozzá tulajdonságértékeket az adott objektum tartalommodellt megvalósító tulajdonságaihoz. A WPF-ben a teljes objektumfa kétféleképpen koncepcionális, és a nyilvános API-nak is jelenthető: logikai faként és vizualizációs faként. A logikai fa és a vizualizációfa közötti különbség nem feltétlenül fontos, de időnként problémákat okozhatnak bizonyos WPF-alrendszerekkel kapcsolatban, és befolyásolhatják a korrektúra- vagy kódválasztást.

Annak ellenére, hogy nem mindig manipulálja közvetlenül a logikai fát vagy a vizualizációs fát, a fák interakciójának fogalmainak megértése hasznos a WPF mint technológia megértéséhez. A WPF valamilyen fa metaforájaként való gondolkodása szintén elengedhetetlen ahhoz, hogy megértsük, hogyan működik a tulajdonságöröklés és az esemény-útválasztás a WPF-ben.

Megjegyzés:

Mivel az objektumfa inkább fogalom, mint egy tényleges API, a koncepciót egy másik módszer az objektumdiagramként felfogni. A gyakorlatban futásidőben olyan kapcsolatok alakulhatnak ki az objektumok között, ahol a fa metaforája meg fog szűnni. Mindazonáltal, különösen az XAML-definiált felhasználói felületen a fa metaforája elég releváns ahhoz, hogy a WPF-dokumentáció többsége az objektumfa kifejezést használja az általános fogalomra való hivatkozáskor.

A logikai fa

A WPF-ben az elemeket visszatartó objektumok tulajdonságainak beállításával tartalmat adhat hozzá a felhasználói felület elemeihez. Például elemeket adhat hozzá egy ListBox vezérlőelemhez a tulajdonságának módosításával Items . Ezzel az ItemCollection elemeket a Items tulajdonságértékébe helyezi. Hasonlóképpen, ha objektumokat szeretne hozzáadni egy DockPanelobjektumhoz, a tulajdonságértékét is módosíthatja Children . Itt objektumokat ad hozzá a UIElementCollection. Példakód: Elem hozzáadása dinamikusan.

Az Extensible Application Markup Language (XAML) alkalmazásban, amikor listaelemeket helyez el egy ListBox elemben, vagy vezérlőket vagy más felhasználói felületi elemeket egy DockPanel elemben, akkor a Items és Children tulajdonságokat is használja, akár explicit, akár implicit módon, ahogyan az alábbi példában is látható.

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

Ha ezt az XAML-t XML-ként dolgozná fel egy dokumentumobjektum-modellben, és az implicit megjegyzéssel ellátott címkéket is belefoglalta volna (ami engedélyezett lett volna), akkor az eredményül kapott XML DOM-fa tartalmazta volna az elemeket, például a <ListBox.Items> és a többi implicit elemet. Az XAML azonban nem így dolgozza fel, amikor a jelölést olvassa és objektumokba ír, az eredményül kapott objektumdiagram nem tartalmazza szó szerint ListBox.Items. Van azonban egy ListBox típusú tulajdonság Items, amely tartalmaz egy ItemCollection, és bár inicializálva van, üres marad, amikor az ItemCollection XAML feldolgozásra kerül. Ezután minden gyermekobjektum-elem, amely tartalomként létezik az ListBox számára, hozzáadásra kerül a ItemCollection-hoz a parser hívásai által a ItemCollection.Add-hez. Az XAML objektumfává való feldolgozásának ez a példája eddig látszólag olyan példa, ahol a létrehozott objektumfa alapvetően a logikai fa.

A logikai fa azonban nem a teljes objektumgráf, amely futásidőben létezik az alkalmazás felhasználói felületén, még akkor sem, ha az XAML implicit szintaxiselemeket is figyelembe kell vegye. Ennek fő oka a vizualizációk és a sablonok. Vegyük például a Button. A logikai fa jelenti a Button objektumot és annak Content sztringjét is. A futásidejű objektumfában azonban ennél a gombnál több is található. A gomb különösen azért jelenik meg a képernyőn, mert egy adott Button vezérlősablont alkalmaztak. Az alkalmazott sablonból származó vizualizációk (például a vizualizáció gomb körüli sötétszürke sablon definiálása Border ) nem jelennek meg a logikai fában, még akkor sem, ha futás közben tekinti meg a logikai fát (például egy bemeneti eseményt kezel a látható felhasználói felületről, majd beolvassa a logikai fát). A sablonvizualizációk megkereséséhez ehelyett meg kell vizsgálnia a vizualizációfát.

További információ arról, hogy az XAML szintaxis hogyan képezi le a létrehozott objektumgráfot, valamint az implicit szintaxist az XAML-ben, lásd: XAML Szintaxis részleteiben vagy XAML a WPF-ben.

A logikai fa célja

A logikai fa azért létezik, hogy a tartalommodellek könnyen iterálhassanak a lehetséges gyermekobjektumaikon, és hogy a tartalommodellek bővíthetőek legyenek. A logikai fa emellett keretrendszert is biztosít bizonyos értesítésekhez, például amikor a logikai fa összes objektuma betöltődik. A logikai fa alapvetően egy keretrendszerszintű futásidejű objektumdiagram közelítése, amely kizárja a vizualizációkat, de számos lekérdezési művelethez megfelelő a saját futásidejű alkalmazás összetétele alapján.

Emellett a statikus és dinamikus erőforráshivatkozásokat úgy oldja fel a rendszer, hogy felfelé halad a kezdeti kérést benyújtó objektum gyűjteményein a logikai fa mentén, majd folytatja tovább a logikai fán, és minden egyes Resources (vagy FrameworkElement) esetén ellenőrzi egy másik FrameworkContentElement értéket, amely tartalmazhat egy Resources értéket, amely esetleg a keresett kulcsot is tartalmazza. A logikai fa akkor használatos az erőforrás-kereséshez, ha a logikai fa és a vizualizációfa is jelen van. Az erőforrás-szótárakról és a keresésről további információt az XAML-erőforrások című témakörben talál.

A logikai fa összetétele

A logikai fa a WPF keretrendszer szintjén van definiálva, ami azt jelenti, hogy a logikai faműveletek szempontjából leginkább releváns WPF-alapelem vagy FrameworkElement vagy FrameworkContentElement. Amint azonban láthatja, ha valóban használja az LogicalTreeHelper API-t, a logikai fa néha olyan csomópontokat tartalmaz, amelyek nem FrameworkElement vagy FrameworkContentElement. Például a logikai fa egy Text sztring TextBlock értékét jelenti.

A logikai fa felülírása

A speciális vezérlőszerzők felülbírálhatják a logikai fát, ha felülbírálnak több API-t, amelyek meghatározzák, hogy egy általános objektum vagy tartalommodell hogyan adja hozzá vagy távolítja el az objektumokat a logikai fán belül. A logikai fa felülbírálásához lásd a Logikai fa felülbírálása című témakört.

Tulajdonságérték öröklése

A tulajdonságérték-öröklés hibrid fán keresztül működik. Az a tényleges metaadat, amely tartalmazza a tulajdonságöröklést lehetővé tevő Inherits tulajdonságot, a WPF keretrendszer-szintű FrameworkPropertyMetadata osztálya. Ezért mind az eredeti értéket tartalmazó szülőnek, mind az azt öröklő gyermekobjektumnak FrameworkElement vagy FrameworkContentElement kell lennie, és mindkettőnek része kell lennie egy logikai fának. Azonban a meglévő, tulajdonságöröklést támogató WPF-tulajdonságok esetében a tulajdonságérték-öröklés képes folytatódni egy közbeiktatott objektumon keresztül, amely nem része a logikai fának. Ez főként azért fontos, mert a sablonelemek az örökölt tulajdonságértékeket használják, amelyeket vagy a sablonos példányon, vagy a lap szintjén még magasabb összetételi szinten állítottak be, ezért magasabb helyet foglalnak el a logikai fában. Ahhoz, hogy a tulajdonságértékek öröklése egységesen működjön egy ilyen határvonalon, az öröklő tulajdonságot csatolt tulajdonságként kell regisztrálni, és ezt a mintát kell követnie, ha egyéni függőségi tulajdonságot szeretne definiálni tulajdonságöröklési viselkedéssel. A tulajdonságörökléshez használt pontos fát nem lehet teljesen előre látni egy segédosztály segédprogram módszerével, még futásidőben sem. További információ: Tulajdonságérték öröklése.

A vizuális fa

A logikai fa koncepciója mellett a WPF-ben is létezik vizualizációs fa. A vizualizációfa az alaposztály által képviselt vizuális objektumok szerkezetét Visual írja le. Amikor sablont ír egy vezérlőelemhez, definiálja vagy újradefiniálja a vezérlőre vonatkozó vizualizációs fát. A vizualizációs fa azoknak a fejlesztőknek is érdekes, akik teljesítmény- és optimalizálási okokból alacsonyabb szintű vezérlést szeretnének a rajz felett. A vizuális fa a hagyományos WPF-alkalmazások programozásának részeként az egyik jellemzője, hogy az irányított események eseményútvonalai többnyire a vizuális fa mentén haladnak, nem pedig a logikai fa mentén. Lehet, hogy az irányított esemény viselkedésének finomságait csak akkor érti meg közvetlenül, ha Ön vezérlőfejlesztő. Az események vizualizációs fán keresztüli átirányítása lehetővé teszi a vizualizáció szintjén a kompozíciót megvalósító vezérlőket az események kezeléséhez vagy eseménykészletek létrehozásához.

Fák, tartalomelemek és tartalomgazdák

A tartalomelemek (ezekből ContentElementszármazó osztályok) nem részei a vizualizáció fájának; nem öröklik Visual őket, és nem rendelkeznek vizuális ábrázolással. Ahhoz, hogy egyáltalán megjelenjen egy felhasználói felületen, egy ContentElement olyan tartalomgazda gazdagépen kell üzemeltetni, amely egyszerre logikai Visual fa résztvevője. Általában egy ilyen objektum egy FrameworkElement. Azt is el tudja fogadni, hogy a tartalom gazdagépe némileg hasonlít a tartalom "böngészőjére", és kiválaszthatja, hogyan jeleníthető meg a tartalom a gazdagép által vezérlő képernyőterületen belül. Amikor a tartalom tárolásra kerül, a tartalom részt vehet bizonyos fa strukúráinak folyamataiban, amelyek általában a vizuális fához vannak társítva. A gazda osztály általában olyan implementációs kódot tartalmaz, FrameworkElement amely a tartalom logikai fa alcsomópontain keresztül hozzáad bármely üzemeltetett ContentElement gazda tartalmat az eseményúthoz, annak ellenére, hogy a gazda tartalom nem része a tényleges vizuális fának. Erre azért van szükség, hogy a ContentElement rendszer olyan irányított eseményt generáljon, amely nem önmagához, hanem bármely elemhez irányít.

Fa bejárása

Az LogicalTreeHelper osztály a logikai fa bejárásához biztosítja a GetChildren, GetParentés FindLogicalNode metódusokat. A legtöbb esetben nem kell a meglévő vezérlők logikai fáját átkelnie, mert ezek a vezérlők szinte mindig olyan dedikált gyűjteménytulajdonságként teszik elérhetővé a logikai gyermekelemeiket, amely támogatja a gyűjtemények elérését, például Addindexelőként stb. A fa bejárása főként olyan forgatókönyv, amelyet olyan fejlesztők használnak, akik úgy döntenek, hogy nem a kívánt vezérlőmintákból, például ItemsControl vagy Panel, amelyeknél a gyűjteménytulajdonságok már definiálva vannak, kívánnak származni, és saját gyűjteménytulajdonság-támogatást kívánnak biztosítani.

A vizualizációs fa egy segédosztályt is támogat a vizualizációs fa bejárásához. VisualTreeHelper A vizualizációfát nem lehet olyan kényelmesen elérhetővé tenni vezérlőspecifikus tulajdonságokon keresztül, ezért az VisualTreeHelper osztály az ajánlott módszer a vizualizációs fa bejárására, ha ez a programozási forgatókönyvhöz szükséges. További információért lásd: WPF grafikus renderelés áttekintése.

Megjegyzés:

Néha meg kell vizsgálni egy alkalmazott sablon vizualizációs fáját. Ennek a technikának a használatakor óvatosnak kell lennie. Még akkor is, ha egy vizualizációs fán halad át egy vezérlőn, ahol a sablont definiálja, a vezérlő felhasználói bármikor módosíthatják a sablont a tulajdonság példányokra való beállításával Template , és még a végfelhasználó is befolyásolhatja az alkalmazott sablont a rendszertéma módosításával.

Az irányított események útvonalai faként

Ahogy korábban említettük, az adott irányított események útvonala egy fa egyetlen és előre meghatározott útvonalán halad, amely a vizualizációk és a logikai faábrázolások hibridje. Az eseményútvonal a fán belüli felfelé vagy lefelé haladhat attól függően, hogy az alagút- vagy buborékos útvonalú eseményről van-e szó. Az eseményútvonal koncepciója nem rendelkezik közvetlenül támogató segédosztállyal, amely az eseményútvonal "bejárására" használható, függetlenül attól, hogy ténylegesen útvonalat meghatározó eseményt vált ki. Van egy osztály, amely az útvonalat jelöli, EventRoutede az osztály metódusai általában csak belső használatra használhatók.

Erőforrás-szótárak és fák

Az oldal bejárásával definiált összes Resources kifejezés erőforrások szótárában való keresése alapvetően a logikai fát vizsgálja. A logikai fában nem szereplő objektumok hivatkozhatnak a kulcsos erőforrásokra, de az erőforrás-keresési sorrend azon a ponton kezdődik, ahol az objektum csatlakozik a logikai fához. A WPF-ben csak a logikai facsomópontok tartalmazhatnak Resources olyan tulajdonságot, amely tartalmaz egy ResourceDictionarytulajdonságot, ezért a vizualizációs fa bejárása nem jár előnyökkel, ha kulcsolt erőforrásokat keres egy ResourceDictionary.

Az erőforrás-keresés azonban túlnyúlhat az azonnali logikai fán is. Az alkalmazás-korrektúra esetében az erőforrás-keresés ezután továbbhaladhat az alkalmazásszintű erőforrás-szótárakhoz, majd a statikus tulajdonságokként vagy kulcsként hivatkozott tématámogatási és rendszerértékekhez. A témák maguk is hivatkozhatnak a téma logikai fáján kívüli rendszerértékekre, ha az erőforráshivatkozások dinamikusak. Az erőforrás-szótárakról és a keresési logikáról további információt az XAML-erőforrások című témakörben talál.

Lásd még