Architektura Windows Presentation Foundation
Rozhraní WPF se snaží vývojářům poskytnout komplexní možnosti v návrhu uživatelského prostředí v co nejvyšším možném výkonu a zároveň pohodlnosti práce. Jakým způsobem je tedy tato technologie navržena?
Diagram, který jsem zde uvedl označuje části patřící WPF zeleně a zbytek modře.
Celé WPF je postaveno nad DirectX technologií. Ta v systémech Windows slouží jako API pro přímou komunikaci s hardwarem, nejčastěji grafickou kartou. To zajišťuje, že vykreslování je ve WPF akcelerováno. DirectX se používá například k vykreslování prostředí Windows Aero nebo je velmi často využíván v počítačových hrách.
Jako most mezi DirectX a managed rozhraním, se kterým komunikujeme z C# nebo jiného CLR jazyku, se nazývá milcore - zkratka pro Media Integration Layer. Tato vrstva je unmanaged (běží mimo .NET CLR) a důvodem jejího vzniku je nutnost vysoce výkonného jádra zajištujícím nízko úrovňové procesy ve WPF. Vše, co bylo možné je tedy přesunuto do této vrstvy z důvodů zvýšení výkonu. My s milcore přímo nekomunikujeme.
S vrstvou milcore komunikuje .NET assembly PresentationCore. Ta již běží v rámci CLR (managed) a nabízí to nejzákladnější rozhraní WPF, se kterým můžeme pracovat.
Úplně na vrchu sedí assembly PresentationFramework. Rozšiřuje PresentationCore o komplexní prvky uživatelského prostředí a pokročilejší funkce.
Poslední důležitou knihovnou je WindowsBase. Ta sice nemá nic přímo společného s vykreslováním, ale poskytuje další důležité třídy pro běh WPF. Například Dispatcher popisovaný v jednom z minulých dílů.
Když to shrnu, pro psaní WPF aplikací potřebujete mít referenci v projektu na tyto tři assembly:
- WindowsBase.dll
- PresentationCore.dll
- PresentationFramework.dll
Při založení nového WPF projektu se všechny tyto assembly přidají mezi reference automaticky.
Objektový model Windows Presentation Foundation
Následující odstavce popisují abstraktní typy, od kterých dědí ovládací prvky a potažmo od některých z nich i velká část nevizuálních komponent ve WPF.
DispatcherObject (vazba na Dispatcher)
Tuto třídu jsem popisoval v jednom z předchozích dílů. Její jediný účel je nést informaci o Dispatcher objektu, ke kterému je tento objekt přiřazen. Pomáhá nám tedy určit, v jakém kontextu byl objekt vytvořen a ověřovat, že k němu nepřistupujeme z jiného vlákna.
DispatcherObject použijete jako předka u vaší třídy v případě, že chceme mít k dispozici Dispatcher z vlákna, které instanci vytvořilo. Takto vytvořený objekt má již napevno Dispatcher přiřazený.
DependencyObject (kontejner na vlastnosti)
DependencyObject rozšiřuje třídu DispatcherObject o podporu DependencyProperties. Jedná se o technologický základ pro WPF binding. O této velmi užitečné technologii budu psát až v dalších dílech.
DependencyObject použijete jako předka u tříd, na které se budete chtít odkazovat bindingem z WPF komponent. Ideální při psaní view-modelů.
Visual (renderování)
Třída Visual dědí z DependencyObject a reprezentuje nejnižší základ tříd, které je možné ve WPF vykreslit. Krom této funkce navíc dovoluje provádět různé transformace zobrazení a operace týkající se matematické kontroly, kam vizuálně objekt zasahuje (takzvaný “hit testing”). To se využívá třeba při optimalizacích zobrazování (nevykreslovat objekty, které nejsou vidět, překreslování atp.) nebo u zjišťování, zda jsme se kliknutím trefili na tlačítko.
Tato třída zároveň zajišťuje komunikaci s milcore vrstvou pro vykreslování.
UIElement (pozicování, vstup od uživatele)
UIElement je abstraktní třída popisující element uživatelského prostředí.
Na rozdíl od třídy Visual přidává k podpoře vykreslování navíc podporu layoutu (rozložení prvků). To je jedna ze skvěle vyřešených funkcí WPF. V porovnání s Windows Forms, kde se pracuje s absolutním pozicováním rozšířeným o pár nastavení je zde vše vyřešeno mnohem elegantněji s možností pozicování plně měnit. O tom ale více v jiných dílech.
Dále tato třída implementuje IInputElement rozhraní pro práci se vstupem od uživatele.
V celém WPF se UIElement bere jako základní třída představující vizuální prvek. Využijeme ji, pokud se rozhodneme psát vlastní komponenty se zcela vlastním chováním.
FrameworkElement (binding, styles, templates)
FrameworkElement rozšiřuje UIElement o další důležité funkce. Konkrétně data-binding, templates (šablonování) a styles (stylování). Podrobněji se jim budu věnovat v dalších dílech.
Dědí z něj všechny běžné vizuální komponenty ve WPF.
Control (předpřipravené templatování)
Control je už jen taková třešnička na dortu. Jako jediná z představených tříd není abstraktní a tudíž můžeme vytvořit její instanci. Podporuje předpřipravenou možnost šablonování vzhledu odvozených komponent.
Shrnutí
Rozhraní WPF nabízí ještě celou řadu dalších tříd. Ty uvedené však považuji z pohledu architektury za nejdůležitější, protože jsou základem fungování celého frameworku. Zároveň se v průběhu seriálu budu na jednotlivé třídy odkazovat a hlouběji vysvětlovat jejich funkce a jak z nich těžit.
V příští díle popisuji, jakým způsobem reaguje na změnu hodnoty DPI systému aplikace napsaná ve WPF a proč je tento stav ve Windows Forms obvykle problém.