Architektura WPF

Toto téma obsahuje prohlídku hierarchie tříd WPF (Windows Presentation Foundation). Popisuje většinu hlavních subsystémů WPF a popisuje, jak interagují. Také podrobně popisuje některé volby provedené architekty WPF.

System.Object

Primární programovací model WPF je vystavený prostřednictvím spravovaného kódu. V rané fázi návrhu WPF došlo k řadě debat o tom, kde by měla být čára vytažena mezi spravovanými součástmi systému a nespravovanými. MODUL CLR poskytuje řadu funkcí, díky kterým je vývoj produktivnější a robustnější (včetně správy paměti, zpracování chyb, systému běžných typů atd.), ale za cenu.

Hlavní komponenty WPF jsou znázorněny na obrázku níže. Červené části diagramu (PresentationFramework, PresentationCore a milcore) jsou hlavní části kódu WPF. Z nich je to jen jedna nespravovaná komponenta – milcore. Milcore je napsaný v nespravovaném kódu, který umožňuje úzkou integraci s DirectX. Veškerý displej v WPF se provádí prostřednictvím modulu DirectX, který umožňuje efektivní vykreslování hardwaru a softwaru. WPF také vyžaduje přesnou kontrolu nad pamětí a spouštěním. Kompoziční motor v milcore je extrémně citlivý na výkon a vyžaduje, aby se mnoho výhod CLR získal výkon.

The position of WPF within the .NET Framework.

Komunikace mezi spravovanými a nespravovanými částmi WPF je popsána dále v tomto tématu. Zbývající část spravovaného programovacího modelu je popsaná níže.

System.Threading.DispatcherObject

Většina objektů v WPF je odvozena od DispatcherObject, který poskytuje základní konstrukty pro zpracování souběžnosti a threading. WPF je založen na systému zasílání zpráv implementovaném dispečerem. To funguje podobně jako známé čerpadlo zpráv Win32; dispečer WPF ve skutečnosti používá k provádění volání mezi vlákny zprávy User32.

Při diskusi o souběžnosti ve WPF – dispečera a spřažení vláken existují skutečně dva základní koncepty.

Během fáze návrhu WPF bylo cílem přejít na jedno vlákno provádění, ale model bez vláken "spřažení". Spřažení vláken nastane, když komponenta používá identitu spuštěného vlákna k uložení určitého typu stavu. Nejběžnější formou je použití místního úložiště vláken (TLS) k uložení stavu. Spřažení vláken vyžaduje, aby každé logické vlákno spouštění bylo vlastněno pouze jedním fyzickým vláknem v operačním systému, které může být náročné na paměť. Na konci byl model vláken WPF udržován v synchronizaci s existujícím modelem threadingu User32 s jedním spuštěním s vlákny se spřažením vláken. Hlavním důvodem této interoperability byla interoperabilita – systémy, jako je OLE 2.0, schránka a Internet Explorer, vyžadují provádění spřažení s jedním vláknem (STA).

Vzhledem k tomu, že máte objekty s vlákny STA, potřebujete způsob, jak komunikovat mezi vlákny a ověřit, že jste ve správném vlákně. Tady je role dispečera. Dispečer je základní systém pro odesílání zpráv s několika frontami s prioritami. Mezi příklady zpráv patří nezpracovaná vstupní oznámení (přesunutá myší), funkce architektury (rozložení) nebo uživatelské příkazy (provedení této metody). Odvozením z DispatcherObjectobjektu CLR, který má chování STA, a dostanete ukazatel na dispečera při vytváření.

System.Windows.DependencyObject

Jednou z primárních architekturních filozofie používaných při sestavování WPF byla předvolba vlastností před metodami nebo událostmi. Vlastnosti jsou deklarativní a umožňují snadněji určit záměr místo akce. To také podporuje modelem řízený systém nebo systém řízený daty pro zobrazení obsahu uživatelského rozhraní. Tato filozofie měla zamýšlený účinek na vytvoření více vlastností, se kterými byste se mohli svázat, aby bylo možné lépe řídit chování aplikace.

Aby bylo možné mít více systémů řízených vlastnostmi, bohatší systém vlastností, než jaký modul CLR poskytuje, byl potřeba. Jednoduchým příkladem této pestrosti je oznámení o změnách. Pokud chcete povolit obousměrnou vazbu, potřebujete obě strany vazby, aby podporovaly oznámení o změnách. Pokud chcete mít chování svázané s hodnotami vlastností, musíte být upozorněni, když se hodnota vlastnosti změní. Rozhraní Microsoft .NET Framework má rozhraní INotifyPropertyChange, které umožňuje objekt publikovat oznámení o změnách, ale je volitelný.

WPF poskytuje bohatší systém vlastností odvozený od DependencyObject typu. Systém vlastností je skutečně systém vlastností "závislost" v tom, že sleduje závislosti mezi výrazy vlastností a automaticky revaliduje hodnoty vlastností při změně závislostí. Pokud například máte vlastnost, která dědí (například FontSize), systém se automaticky aktualizuje, pokud se vlastnost změní u nadřazeného prvku, který dědí hodnotu.

Základem systému vlastností WPF je koncept výrazu vlastnosti. V této první verzi WPF je systém výrazů vlastností uzavřen a výrazy jsou poskytovány jako součást architektury. Výrazy jsou důvodem, proč systém vlastností nemá pevně zakódovanou datovou vazbu, styling nebo dědičnost, ale spíše poskytuje pozdější vrstvy v rámci rozhraní.

Systém vlastností také poskytuje zhuštěné ukládání hodnot vlastností. Vzhledem k tomu, že objekty můžou mít desítky (pokud ne stovky) vlastností a většina hodnot je ve výchozím stavu (zděděno, nastaveno podle stylů atd.), ne každá instance objektu musí mít plnou váhu každé vlastnosti definované v ní.

Poslední novou funkcí systému vlastností je pojem připojených vlastností. Prvky WPF jsou založeny na principu složení a opětovného použití komponent. Často se jedná o případ, že některé obsahující elementy (například Grid element rozložení) potřebují další data o podřízených prvcích, aby bylo možné řídit jeho chování (například informace o řádku nebo sloupci). Místo přidružení všech těchto vlastností ke každému prvku může jakýkoli objekt poskytovat definice vlastností pro jakýkoli jiný objekt. To se podobá funkcím "expando" JavaScriptu.

System.Windows.Media.Visual

Když je systém definovaný, dalším krokem jsou pixely nakreslené na obrazovku. Třída Visual poskytuje pro vytvoření stromu vizuálních objektů, z nichž každý volitelně obsahuje pokyny pro kreslení a metadata o tom, jak tyto instrukce vykreslit (výřez, transformace atd.). Visual je navržen tak, aby byl extrémně jednoduchý a flexibilní, takže většina funkcí nemá žádné veřejné rozhraní API a spoléhá na chráněné funkce zpětného volání.

Visual je skutečně vstupním bodem systému složení WPF. Visual je bod připojení mezi těmito dvěma subsystémy, spravovaným rozhraním API a nespravovanými milcore.

WPF zobrazuje data procházením nespravovaných datových struktur spravovaných milcore. Tyto struktury, označované jako uzly složení, představují hierarchický strom zobrazení s pokyny pro vykreslování na každém uzlu. Tento strom, který je znázorněn na pravé straně obrázku níže, je přístupný pouze prostřednictvím protokolu zasílání zpráv.

Při programování WPF vytvoříte Visual prvky a odvozené typy, které interně komunikují s kompozičním stromem prostřednictvím tohoto protokolu zasílání zpráv. Každý Visual z WPF může vytvořit jeden, žádný nebo několik skládání uzlů.

The Windows Presentation Foundation Visual Tree.

Zde je velmi důležitý podrobný přehled architektury – celý strom vizuálů a pokynů pro kreslení se ukládá do mezipaměti. Z hlediska grafiky používá WPF zachovaný vykreslovací systém. To umožňuje systému znovu nakreslit vysoké obnovovací frekvence bez blokování systému složení u zpětných volání do uživatelského kódu. To pomáhá zabránit vzhledu nereagující aplikace.

Další důležitý detail, který není ve skutečnosti znatelný v diagramu, je způsob, jakým systém ve skutečnosti provádí složení.

V user32 a GDI systém funguje na okamžitém režimu výřez systému. Když je potřeba vykreslit komponentu, systém vytvoří ořezy, mimo které komponenta nesmí dotýkat pixelů, a pak se zobrazí výzva k vykreslení pixelů v daném rámečku. Tento systém funguje velmi dobře v paměťových omezených systémech, protože když se něco změní, stačí se dotkne jenom ovlivněné komponenty – žádné dvě komponenty nikdy nepřispívají k barvě jednoho pixelu.

WPF používá model obrazu "malířský algoritmus". To znamená, že místo vystřižení jednotlivých komponent se každá komponenta zobrazí zezadu do přední části displeje. To umožňuje, aby každá komponenta vykreslovala zobrazení předchozí komponenty. Výhodou tohoto modelu je, že můžete mít složité, částečně průhledné obrazce. Díky dnešnímu modernímu grafickému hardwaru je tento model poměrně rychlý (což nebylo případ, kdy byl vytvořen User32/ GDI).

Jak už bylo zmíněno dříve, základní filozofie WPF spočívá v přechodu k deklarativnímu modelu programování zaměřenému na vlastnosti. Ve vizuálním systému se to zobrazí na několika zajímavých místech.

Za prvé, pokud si myslíte o grafickém systému zachovaného režimu, je to opravdu posun od imperativního modelu typu DrawLine/DrawLine do modelu orientovaného na data – nový Line()/new Line(). Tento přechod na vykreslování řízené daty umožňuje vyjádřit složité operace s pokyny výkresu pomocí vlastností. Typy odvozené z Drawing jsou v podstatě objektový model pro vykreslování.

Za druhé, pokud vyhodnotíte animační systém, uvidíte, že je téměř úplně deklarativní. Místo toho, aby vývojář musel vypočítat další umístění nebo další barvu, můžete animace vyjádřit jako sadu vlastností objektu animace. Tyto animace pak můžou vyjádřit záměr vývojáře nebo návrháře (přesuňte toto tlačítko sem za 5 sekund) a systém dokáže určit nejúčinnější způsob, jak toho dosáhnout.

System.Windows.UIElement

UIElement definuje základní subsystémy, včetně rozložení, vstupu a událostí.

Rozložení je základní koncept WPF. V mnoha systémech existuje pevná sada modelů rozložení (HTML podporuje tři modely pro rozložení; tok, absolutní a tabulky) nebo žádný model pro rozložení (User32 skutečně podporuje pouze absolutní umístění). WPF začal s předpokladem, že vývojáři a návrháři chtěli flexibilní, rozšiřitelný model rozložení, který by mohl být řízen hodnotami vlastností místo imperativní logiky. UIElement Na úrovni se zavádí základní kontrakt pro rozložení – dvoufázový model s Measure a Arrange projde.

Measure umožňuje komponentě určit, jakou velikost by chtěla vzít. Toto je samostatná fáze od Arrange toho, že existuje mnoho situací, kdy nadřazený prvek požádá dítě, aby několikrát změřil jeho optimální pozici a velikost. Skutečnost, že nadřazené prvky požádají podřízené prvky, aby změřily další klíčovou filozofie WPF – velikost obsahu. Všechny ovládací prvky wpf podporují schopnost velikost na přirozenou velikost jejich obsahu. Díky tomu je lokalizace mnohem jednodušší a umožňuje dynamické rozložení prvků při změně velikosti. Fáze Arrange umožňuje nadřazené umístění a určení konečné velikosti každého podřízeného objektu.

Hodně času se často věnuje mluvení o výstupní straně WPF – Visual a souvisejících objektech. Na vstupní straně však existuje obrovské množství inovací. Pravděpodobně nejzákladnější změnou vstupního modelu pro WPF je konsis režim stanu l, pomocí kterých jsou vstupní události směrovány systémem.

Vstup pochází jako signál ovladače zařízení v režimu jádra a směruje se na správný proces a vlákno prostřednictvím složitého procesu zahrnujícího jádro Windows a User32. Jakmile se zpráva User32 odpovídající vstupu směruje do WPF, převede se na nezpracovanou vstupní zprávu WPF a odešle se dispečerovi. WPF umožňuje převést nezpracované vstupní události na více skutečných událostí, což umožňuje implementaci funkcí, jako je MouseEnter, na nízké úrovni systému s garantovaným doručením.

Každá vstupní událost se převede na aspoň dvě události – událost "preview" a skutečnou událost. Všechny události ve WPF mají představu o směrování přes strom prvků. Události jsou označeny jako "bubliny", pokud procházejí z cíle směrem nahoru do kořene a jsou označeny jako "tunel", pokud začínají v kořenovém adresáři a procházejí směrem dolů k cíli. Vstupní tunel událostí náhledu, který umožňuje libovolnému prvku ve stromu filtrovat nebo provádět akce s událostí. Běžné události (bez náhledu) pak bubliny z cíle až do kořenového adresáře.

Díky tomuto rozdělení mezi tunelovou a bublinovou fází funguje implementace funkcí, jako jsou akcelerátory klávesnice, konzistentním způsobem ve složeném světě. V user32 byste implementovali akcelerátory klávesnice tak, že máte jednu globální tabulku obsahující všechny akcelerátory, které chcete podporovat (Ctrl+N mapování na "Nový"). V dispečeru pro vaši aplikaci byste volali TranslateAccelerator , který by zašifroval vstupní zprávy v User32 a určil, jestli nějaká shoda s registrovaným akcelerátorem. Ve WPF by to nefungilo, protože systém je plně "kompozibilní" – jakýkoli prvek dokáže zpracovat a použít jakýkoli akcelerátor klávesnice. Tento dvoufázový model pro vstup umožňuje komponentám implementovat vlastní "TranslateAccelerator".

Pokud chcete provést tento krok dále, UIElement představíme si také pojem CommandBindings. Systém příkazů WPF umožňuje vývojářům definovat funkce z hlediska koncového bodu příkazu – něco, co implementuje ICommand. Vazby příkazů umožňují elementu definovat mapování mezi vstupním gestem (Ctrl+N) a příkazem (Nový). Jak vstupní gesta, tak definice příkazů jsou rozšiřitelné a dají se připojit společně v době použití. Díky tomu je například triviální, aby koncový uživatel mohl přizpůsobit vazby klíčů, které chce použít v rámci aplikace.

K tomuto bodu v tématu se zaměřily "základní" funkce WPF – funkce implementované v sestavení PresentationCore. Při sestavování WPF byl požadovaný výsledek čistým oddělením základních částí (jako je kontrakt pro rozložení s měřením a uspořádáním) a částí architektury (jako je implementace konkrétního rozložení, jako je například implementace konkrétního rozložení).Grid Cílem bylo poskytnout bod rozšiřitelnosti v zásobníku, který by v případě potřeby umožnil externím vývojářům vytvářet vlastní architektury.

System.Windows.FrameworkElement

FrameworkElement lze se podívat dvěma různými způsoby. Zavádí sadu zásad a přizpůsobení subsystémů zavedených v nižších vrstvách WPF. Zavádí také sadu nových subsystémů.

Primární zásada, kterou zavádí, se řídí rozložením FrameworkElement aplikace. FrameworkElement vychází ze základního kontraktu rozložení zavedeného UIElement a přidává pojem "slot" rozložení, který autorům rozložení usnadňuje konzistentní sadu sémantiky rozložení řízené vlastností. Vlastnosti jako HorizontalAlignment, , MinWidthVerticalAlignmenta Margin (pro pojmenování několika) poskytují všem komponentám odvozeným z FrameworkElement konzistentního chování uvnitř kontejnerů rozložení.

FrameworkElement poskytuje také snadnější vystavení rozhraní API pro mnoho funkcí nalezených v základních vrstvách WPF. Poskytuje například FrameworkElement přímý přístup k animaci prostřednictvím BeginStoryboard metody. A Storyboard poskytuje způsob, jak skriptovat více animací proti sadě vlastností.

Dvě nejdůležitější věci, které FrameworkElement představují datové vazby a styly.

Subsystém datové vazby ve WPF by měl být relativně známý pro každého, kdo použil model Windows Forms nebo ASP.NET k vytvoření uživatelského rozhraní aplikace. V každém z těchto systémů existuje jednoduchý způsob, jak vyjádřit, že chcete, aby jedna nebo více vlastností z daného prvku byla vázána na část dat. WPF má úplnou podporu vazby vlastností, transformace a vazby seznamu.

Jednou z nejzajímavějších funkcí datové vazby ve WPF je zavedení šablon dat. Šablony dat umožňují deklarativní určení způsobu vizualizace části dat. Místo vytvoření vlastního uživatelského rozhraní, které lze svázat s daty, můžete místo toho problém obejít a nechat data určit zobrazení, které se vytvoří.

Styling je opravdu jednoduchá forma datové vazby. Pomocí stylů můžete vytvořit vazbu sady vlastností ze sdílené definice na jednu nebo více instancí elementu. Styly se aplikují na prvek buď explicitním odkazem (nastavením Style vlastnosti), nebo implicitně přidružením stylu k typu CLR elementu.

System.Windows.Controls.Control

Nejdůležitější funkcí ovládacího prvku je šablonování. Pokud uvažujete o systému složení WPF jako systému vykreslování zachovaný režim, šablonování umožňuje ovládacímu prvku popsat jeho vykreslování parametrizovaným deklarativním způsobem. A ControlTemplate není ve skutečnosti nic víc než skript k vytvoření sady podřízených prvků s vazbami na vlastnosti nabízené ovládacím prvku.

Controlposkytuje sadu vlastností akcií , , ForegroundBackground, Padding, pojmenovat několik, které autoři šablon pak mohou použít k přizpůsobení zobrazení ovládacího prvku. Implementace ovládacího prvku poskytuje datový model a model interakce. Model interakce definuje sadu příkazů (například Zavřít pro okno) a vazby na vstupní gesta (například kliknutí na červené X v horním rohu okna). Datový model poskytuje sadu vlastností pro přizpůsobení modelu interakce nebo přizpůsobení zobrazení (určené šablonou).

Toto rozdělení mezi datový model (vlastnosti), model interakce (příkazy a události) a model zobrazení (šablony) umožňuje úplné přizpůsobení vzhledu a chování ovládacího prvku.

Běžným aspektem datového modelu ovládacích prvků je kon režim stanu l. Pokud se podíváte na ovládací prvek jako Button, uvidíte, že má vlastnost s názvem "Content" typu Object. V model Windows Forms a ASP.NET by tato vlastnost obvykle byla řetězcem , ale omezuje typ obsahu, který můžete vložit do tlačítka. Obsah tlačítka může být jednoduchý řetězec, složitý datový objekt nebo celý strom elementu. V případě datového objektu se šablona dat používá k vytvoření zobrazení.

Shrnutí

WPF je navržený tak, aby umožňoval vytvářet dynamické prezentační systémy řízené daty. Každá část systému je navržená tak, aby vytvářela objekty prostřednictvím sad vlastností, které řídí chování. Datová vazba je základní součástí systému a je integrovaná v každé vrstvě.

Tradiční aplikace vytvoří zobrazení a pak vytvoří vazbu na některá data. Ve WPF se vše o ovládacím prvku, každém aspektu zobrazení, generuje pomocí určitého typu datové vazby. Text nalezený uvnitř tlačítka se zobrazí vytvořením složeného ovládacího prvku uvnitř tlačítka a vazbou jeho zobrazení na vlastnost obsahu tlačítka.

Když začnete s vývojem aplikací založených na WPF, mělo by to být velmi známé. Vlastnosti, použití objektů a datové vazby můžete nastavit velmi stejným způsobem, jako můžete použít model Windows Forms nebo ASP.NET. S hlubším zkoumáním architektury WPF zjistíte, že existuje možnost vytváření mnohem bohatších aplikací, které v zásadě považují data za základní ovladač aplikace.

Viz také