Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a témakör a Windows Presentation Foundation (WPF) osztályhierarchiájának bemutatóját ismerteti. A WPF fő alrendszereinek többségét lefedi, és leírja, hogyan működnek együtt. Emellett részletezi a WPF tervezőinek néhány döntését is.
System.Object
Az elsődleges WPF programozási modell felügyelt kóddal érhető el. A WPF tervezési fázisának korai szakaszában számos vita folyt arról, hogy hol kell húzni a vonalat a rendszer felügyelt összetevői és a nem felügyeltek között. A CLR számos olyan funkciót biztosít, amelyek hatékonyabbá és robusztusabbá teszik a fejlesztést (beleértve a memóriakezelést, a hibakezelést, a gyakori típusrendszereket stb.), de ezek költségesek.
A WPF fő összetevőit az alábbi ábra szemlélteti. A diagram piros szakaszai (PresentationFramework, PresentationCore és milcore) a WPF fő kódrészletei. Ezek közül csak egy nem felügyelt összetevő – milcore. A Milcore nem felügyelt kódban van megírva, hogy szoros integrációt lehessen lehetővé tenni a DirectX-lel. A WPF-ben minden megjelenítés a DirectX motoron keresztül történik, ami hatékony hardver- és szoftvermegjelenítést tesz lehetővé. A WPF a memória és a végrehajtás finom vezérlését is megkövetelte. A milcore összetételű motor rendkívül teljesítményérzékeny, és a CLR számos előnyét kellett feladnia a teljesítmény eléréséhez.
A WPF felügyelt és nem felügyelt részei közötti kommunikációt a témakör későbbi részében tárgyaljuk. A felügyelt programozási modell fennmaradó részét az alábbiakban ismertetjük.
System.Threading.DispatcherObject
A WPF legtöbb objektuma a DispatcherObject-ból származik, amely az alapvető szerkezeteket biztosítja az egyidejűség és szálkezelés kezelésére. A WPF a diszpécser által implementált üzenetkezelési rendszeren alapul. Ez úgy működik, mint a jól ismert Win32 üzenetszivattyú; A WPF-diszpécser valójában User32-üzeneteket használ a szálközi hívások végrehajtásához.
Valójában két alapvető fogalmat kell megérteni az egyidejűség WPF-ben való megvitatásakor – a diszpécser és a szál affinitása.
A WPF tervezési fázisában az volt a cél, hogy egyetlen végrehajtási szál használatára térjünk át, de egy olyan modellre, amely nem kötődik szálhoz. A szál affinitása akkor fordul elő, ha egy összetevő a végrehajtó szál identitását használja valamilyen állapot tárolására. Ennek leggyakoribb formája a szál helyi tárolójának (TLS) használata az állapot tárolásához. A szál affinitása megköveteli, hogy a végrehajtás minden logikai szála csak egy fizikai szál tulajdonában legyen az operációs rendszerben, ami memóriaigényessé válhat. Végül a WPF szálmodellje szinkronban maradt a meglévő User32 szálmodellel, amely egyszálas végrehajtást és szál affinitást eredményezett. Ennek elsődleges oka az együttműködési képesség volt – az olyan rendszerek, mint az OLE 2.0, a vágólap és az Internet Explorer, mind egyetlen szál affinitás (STA) végrehajtására van szükség.
Mivel sta-szálkezeléssel rendelkező objektumokkal rendelkezik, módot kell adnia a szálak közötti kommunikációra, és ellenőriznie kell, hogy a megfelelő szálon van-e. Itt rejlik a diszpécser szerepe. A kézbesítő egy alapszintű üzenetküldési rendszer, amely több prioritású üzenetsort tartalmaz. Az üzenetek közé tartoznak például a nyers beviteli értesítések (egérrel áthelyezve), a keretrendszerfüggvények (elrendezés) vagy a felhasználói parancsok (a metódus végrehajtása). Az DispatcherObject-tól kiindulva Ön létrehoz egy CLR-objektumot, amely STA-viselkedéssel rendelkezik, és létrehozásakor kap egy mutatót egy diszpécserre.
System.Windows.FüggőségiObjektum
A WPF építéséhez használt egyik elsődleges architektúrafilozófia a módszerek vagy események tulajdonságainak előnyben részesítése volt. A tulajdonságok deklaratívak, és lehetővé teszik a szándék egyszerűbb megadását művelet helyett. Ez egy modellalapú vagy adatvezérelt rendszert is támogatott a felhasználói felület tartalmának megjelenítéséhez. Ennek a filozófiának az volt a célja, hogy több olyan tulajdonságot hozzon létre, amelyekhez kapcsolódhat, hogy jobban szabályozhassa egy alkalmazás viselkedését.
Ahhoz, hogy a rendszer több tulajdonságot tudjon vezérelni, a CLR által biztosítottnál gazdagabb tulajdonságrendszerre volt szükség. Erre a gazdagságra egyszerű példa a változásértesítések. A kétirányú kötés engedélyezéséhez a kötés mindkét oldalára szüksége van a változásértesítés támogatásához. Ahhoz, hogy a viselkedés a tulajdonságértékekhez legyen kötve, értesítést kell kapnia a tulajdonságérték változásakor. A Microsoft .NET-keretrendszer egy INotifyPropertyChangefelülettel rendelkezik, amely lehetővé teszi az objektumok számára a változásértesítések közzétételét, de ez nem kötelező.
A WPF gazdagabb tulajdonságrendszert biztosít, amely a DependencyObject típusból származik. A tulajdonságrendszer valójában egy "függőség" tulajdonságrendszer, amelyben nyomon követi a tulajdonságkifejezések közötti függőségeket, és automatikusan újraértékeli a tulajdonságértékeket a függőségek változásakor. Ha például olyan tulajdonsága van, amely örökli (például FontSize), a rendszer automatikusan frissül, ha a tulajdonság egy olyan elem szülőjén változik, amely örökli az értéket.
A WPF tulajdonságrendszer alapja egy tulajdonságkifejezés fogalma. A WPF első kiadásában a tulajdonságkifejezési rendszer bezárul, és a kifejezések mind a keretrendszer részeként jelennek meg. A kifejezések miatt a tulajdonságrendszer nem rendelkezik szigorúan kódolt adatkötéssel, stílussal vagy örökléssel, hanem a keretrendszer későbbi rétegei biztosítják.
A tulajdonságrendszer a tulajdonságértékek ritka tárolását is biztosítja. Mivel az objektumok több tucat (ha nem több száz) tulajdonsággal rendelkezhetnek, és az értékek többsége alapértelmezett állapotban van (öröklött, stílusok szerint vannak beállítva stb.), nem minden objektumpéldánynak kell minden tulajdonság teljes súlyával rendelkeznie rajta.
A tulajdonságrendszer utolsó új funkciója a csatolt tulajdonságok fogalma. A WPF-elemek az összetétel és az összetevők újrafelhasználásának elvére épülnek. Gyakran előfordul, hogy egyes elemeknek (például egy Grid elrendezéselemnek) további adatokra van szüksége a gyermekelemeken a viselkedés szabályozásához (például a Sor/Oszlop információhoz). Ahelyett, hogy az összes tulajdonságot minden elemhez társítanák, bármely objektum megadhat tulajdonságdefiníciókat bármely más objektumhoz. Ez hasonló a JavaScript "expando" funkcióihoz.
System.Windows.Media.Visual
A rendszer definiálása után a következő lépés a képpontok képernyőre rajzolása. A Visual osztály vizuális objektumok fáját készíti el, amelyek opcionálisan rajzi utasításokat és metaadatokat tartalmaznak az utasítások megjelenítéséhez (kivágás, átalakítás stb.). Visual rendkívül könnyűnek és rugalmasnak tervezték, így a funkciók többsége nem rendelkezik nyilvános API-kitettséggel, és erősen támaszkodik a védett visszahívási funkciókra.
Visual valójában a WPF összeállítási rendszer belépési pontja. Visual a két alrendszer, a felügyelt API és a nem felügyelt milcore közötti kapcsolati pont.
A WPF a milcore által felügyelt nem felügyelt adatstruktúrákon keresztül jeleníti meg az adatokat. Ezek a szerkezetek, az úgynevezett kompozíciós csomópontok egy hierarchikus megjelenítési fát képviselnek az egyes csomópontok megjelenítési utasításaival. Ez a fa, amely az alábbi ábra jobb oldalán látható, csak üzenetkezelési protokollon keresztül érhető el.
A WPF programozása során Visual elemeket és származtatott típusokat hoz létre, amelyek belsőleg kommunikálnak a kompozíciós fával ezen az üzenetkezelési protokollon keresztül. A WPF minden Visual létrehozhat egy, egyetlen vagy több összeállítási csomópontot.
Itt egy nagyon fontos építészeti részletre kell odafigyelni – a vizualizációk és a rajzutasítások teljes fája gyorsítótárazva van. Grafikus értelemben a WPF megtartott renderelési rendszert használ. Ez lehetővé teszi, hogy a rendszer magas frissítési sebességgel újrafestse anélkül, hogy az összeállítási rendszer blokkolta a visszahívásokat a felhasználói kódra. Ez segít megelőzni a nem válaszoló alkalmazások megjelenését.
Egy másik fontos részlet, amely nem igazán észrevehető a diagramon, hogy a rendszer hogyan végzi el a kompozíciót.
A User32-ben és a GDI-ben a rendszer egy azonnali módú vágórendszeren működik. Amikor egy összetevőt renderelni kell, a rendszer létrehoz egy kivágási határokat, amelyeken kívül az összetevő nem érheti el a képpontokat, majd az összetevőt arra kéri, hogy képpontokat festsen a dobozba. Ez a rendszer nagyon jól működik a memóriakorlátozott rendszerekben, mert ha valami megváltozik, csak az érintett összetevőt kell megérinteni – egyetlen képpont színéhez sem járul hozzá két összetevő.
A WPF egy "festői algoritmus" festőmodellt használ. Ez azt jelenti, hogy az egyes összetevők kivágása helyett az egyes összetevőket arra kérik, hogy rendereljenek hátulról a kijelző elejére. Így minden összetevő átfestheti az előző összetevő kijelzőjét. Ennek a modellnek az az előnye, hogy összetett, részben átlátszó alakzatokkal rendelkezhet. A mai modern grafikus hardverrel ez a modell viszonylag gyors működésű (ami nem így volt, amikor a User32/ GDI létrejött).
Ahogy korábban említettük, a WPF alapvető filozófiája a programozás deklaratívabb, "tulajdonságközpontú" modelljére való áttérés. A vizualizációs rendszerben ez néhány érdekes helyen jelenik meg.
Először is, ha a megtartott módú grafikus rendszerre gondol, ez valójában egy imperatív DrawLine/DrawLine típusú modellről egy adatorientált modellre – új Vonal()/új vonal() felé halad. Az adatvezérelt renderelésre való áttérés lehetővé teszi a rajzi utasítások összetett műveleteinek tulajdonságok használatával történő kifejezését. A Drawing származó típusok gyakorlatilag a renderelés objektummodellje.
Másodszor, ha kiértékeli az animációs rendszert, látni fogja, hogy szinte teljesen deklaratív. Ahelyett, hogy egy fejlesztőnek ki kellene számítania a következő helyet vagy a következő színt, az animációkat tulajdonságok halmazaként fejezheti ki egy animációs objektumon. Ezek az animációk ezután kifejezhetik a fejlesztő vagy tervező szándékát (ezt a gombot innen 5 másodperc alatt áthelyezhetik), és a rendszer meghatározhatja ennek leghatékonyabb módját.
System.Windows.UIElement
UIElement meghatározza az alapvető alrendszereket, beleértve az elrendezést, a bemenetet és az eseményeket.
Az elrendezés a WPF alapkoncepciója. Számos rendszerben rögzített elrendezési modellek vannak (a HTML három elrendezési modellt támogat, a folyamatokat, az abszolút értékeket és a táblázatokat), vagy nincs elrendezési modell (a User32 valóban csak az abszolút elhelyezést támogatja). A WPF azzal a feltételezéssel kezdődött, hogy a fejlesztők és a tervezők rugalmas, bővíthető elrendezési modellt szeretnének, amelyet tulajdonságértékek vezérelhetnek, nem pedig imperatív logikát. A UIElement szintjén bevezetik az elrendezés alapszerződését – egy két fázisú modellel, amely Measure és Arrange szakaszokkal rendelkezik.
Measure lehetővé teszi egy összetevő számára, hogy meghatározza, mennyi méretet szeretne venni. Ez egy külön fázis a Arrange-tól, mert sok olyan helyzet van, amikor egy szülőelem többször is megkéri a gyermekelemet, hogy többször mérje meg az optimális pozícióját és méretét. Az a tény, hogy a szülőelemek mérésre kérik a gyermekelemeket, a WPF egy másik kulcsfontosságú filozófiáját mutatja be – a tartalom méretét. A WPF minden vezérlője támogatja a tartalom természetes méretre való méretezését. Ez sokkal egyszerűbbé teszi a honosítást, és lehetővé teszi az elemek dinamikus elrendezését a dolgok átméretezésekor. A Arrange fázis lehetővé teszi a szülő számára az egyes gyermekek elhelyezését és végső méretének meghatározását.
Gyakran sok időt töltünk a WPF kimeneti oldaláról való beszélgetéssel – Visual és a kapcsolódó objektumokkal. A bemeneti oldalon azonban rengeteg innováció is van. A WPF bemeneti modelljében valószínűleg a legalapvetőbb változás az a konzisztens modell, amellyel a bemeneti események a rendszeren keresztül lesznek irányítva.
A bemenet egy kernel módú eszközillesztő jeleként jön létre, és a rendszer átirányítja a megfelelő folyamathoz és szálhoz egy bonyolult folyamaton keresztül, amely a Windows kernelt és a User32-t is magában foglalja. Miután a bemenetnek megfelelő User32 üzenet a WPF-hez lett irányítva, a rendszer WPF nyers bemeneti üzenetté alakítja, és elküldi a kézbesítőnek. A WPF lehetővé teszi, hogy a nyers bemeneti események több tényleges eseménysé alakuljanak át, így az olyan funkciók, mint a "MouseEnter" a rendszer alacsony szintjén implementálhatók garantált teljesítéssel.
Minden bemeneti eseményt legalább két eseményre konvertál a rendszer – egy "előzetes verziós" eseményre és a tényleges eseményre. A WPF-ben minden eseményhez társul az elemfán keresztüli útválasztás fogalma. Az eseményeket "buboréknak" mondják, ha egy céltól a fától a gyökérig haladnak, és "alagútnak" mondják őket, ha a gyökérnél indulnak, és lefelé haladnak egy cél felé. Bemeneti előzetes események alagútja, amely lehetővé teszi a fa bármely elemének lehetőséget az esemény szűrésére vagy végrehajtására. A normál (nem előzetes verziójú) események ezután a céltól a gyökérig buborékoznak.
Ez az alagút és a buborék fázis közötti felosztás lehetővé teszi, hogy az olyan funkciók, mint a billentyűzetgyorsítók, egységesen működjenek egy összevont környezetben. A User32-ben a billentyűzetgyorsítókat úgy implementálná, hogy egyetlen globális táblával rendelkezik, amely tartalmazza az összes támogatni kívánt gyorsítót (Ctrl+N leképezés az "Új" értékre). Az alkalmazás diszpécserében TranslateAccelerator hívna meg, amely beszúrná a user32 bemeneti üzeneteit, és megállapítaná, hogy valamelyik megfelel-e egy regisztrált gyorsítónak. A WPF-ben ez nem működik, mert a rendszer teljesen "összeállítható" – bármely elem képes kezelni és használni bármilyen billentyűzetgyorsítót. A kétfázisú bemeneti modell lehetővé teszi az összetevők számára a saját "TranslateAccelerator" implementálását.
Ha ezt az egy lépést tovább szeretné tenni, UIElement a CommandBindings fogalmát is bevezeti. A WPF-parancsrendszer lehetővé teszi a fejlesztők számára, hogy a funkciókat parancsvégpontként határozzák meg, valami, ami implementálja a ICommand-t. A parancskötések lehetővé teszik, hogy egy elem leképezést definiáljon egy bemeneti kézmozdulat (Ctrl+N) és egy parancs (Új) között. A bemeneti kézmozdulatok és a parancsdefiníciók bővíthetőek, és a használat során össze is kapcsolhatók. Ez például triviálissá teszi, hogy egy végfelhasználó testre szabhassa az alkalmazáson belül használni kívánt kulcskötéseket.
A témakör ezen pontjára a WPF – a PresentationCore-szerelvényben implementált funkciók – "alapvető" funkciói kerültek a fókuszba. A WPF létrehozásakor az alapvető elemek (mint a Measure és Arrangeszerződése) és a keret elemek (mint egy adott elrendezés megvalósítása, például a Grid) közötti tiszta elkülönítés volt a cél. A cél egy olyan bővíthetőségi pont biztosítása volt, amely lehetővé teszi a külső fejlesztők számára, hogy szükség esetén saját keretrendszereket hozzanak létre.
System.Windows.FrameworkElement
FrameworkElement kétféleképpen tekintheti meg. Szabályzatokat és testreszabásokat vezet be a WPF alsó rétegeiben bevezetett alrendszereken. Emellett új alrendszereket vezet be.
Az FrameworkElement által bevezetett elsődleges szabályzat az alkalmazáselrendezés körül van. FrameworkElement a UIElement által bevezetett alapszintű elrendezési szerződésre épít, és hozzáadja az elrendezési "pont" fogalmát, amely megkönnyíti az elrendezéskészítők számára, hogy egységes tulajdonságvezérelt elrendezési szemantikával rendelkezzenek. Az olyan tulajdonságok, mint a HorizontalAlignment, VerticalAlignment, MinWidthés Margin (hogy csak néhányat említsünk) az elrendezéstárolókban FrameworkElement konzisztens viselkedésből származó összes összetevőt adják meg.
FrameworkElement egyszerűbb API-kitettséget biztosít a WPF alapvető rétegeiben található számos funkciónak. A FrameworkElement például közvetlen hozzáférést biztosít az animációhoz a BeginStoryboard metóduson keresztül. A Storyboard több animációt is szkriptelhet egy tulajdonságkészlethez.
A két legkritikusabb dolog, amit FrameworkElement bevezet, az adatkötés és a stílusok.
A WPF adatkötési alrendszerének viszonylag ismerősnek kell lennie mindenki számára, aki windowsos űrlapokat vagy ASP.NET használt az alkalmazás felhasználói felületének (UI) létrehozásához. Mindegyik rendszerben egyszerűen kifejezhető, hogy egy adott elem egy vagy több tulajdonságát egy adathoz szeretné kötni. A WPF teljes mértékben támogatja a tulajdonságkötést, az átalakítást és a listakötést.
Az adatkötés egyik legérdekesebb funkciója a WPF-ben az adatsablonok bevezetése. Az adatsablonok lehetővé teszik, hogy deklaratív módon határozza meg az adatok vizualizációjának módját. Az adatokhoz köthető egyéni felhasználói felület létrehozása helyett inkább megfordíthatja a problémát, és hagyhatja, hogy az adatok határozzák meg a létrehozandó megjelenítést.
A stílus tényleg egy könnyű adatkötési forma. A stílus használatával tulajdonságokat, amelyek egy megosztott definícióból származnak, egy vagy több elemhez köthet. A stílusok akár explicit hivatkozással (a Style tulajdonság beállításával), akár az elem CLR-típusával társítva implicit módon vannak alkalmazva.
System.Windows.Controls.Control
A vezérlés legfontosabb funkciója a sablonozás. Ha a WPF összeállítási rendszerét megtartott módú renderelő rendszerként tekinti, a templating lehetővé teszi, hogy a vezérlő paraméteres, deklaratív módon írja le annak renderelését. A ControlTemplate valójában nem más, mint egy szkript, amely gyermekelemeket hoz létre, és a vezérlőelem által kínált tulajdonságokhoz kötéseket biztosít.
Control készlettulajdonságokat biztosít, Foreground, Background, Padding, hogy néhányat említsünk, amelyeket a sablonkészítők ezután a vezérlők megjelenítésének testreszabására használhatnak. A vezérlők implementálása adatmodellt és interakciós modellt biztosít. Az interakciós modell parancsokat (például bezárás egy ablakhoz) és a bemeneti kézmozdulatok kötéseit határozza meg (például az ablak felső sarkában lévő piros X ikonra kattintva). Az adatmodell számos tulajdonságot biztosít az interakciós modell testreszabásához vagy a megjelenítés testreszabásához (amelyet a sablon határoz meg).
Ez az adatmodell (tulajdonságok), az interakciós modell (parancsok és események) és a megjelenítési modell (sablonok) közötti felosztás lehetővé teszi a vezérlő megjelenésének és viselkedésének teljes testreszabását.
A vezérlők adatmodelljének gyakori eleme a tartalommodell. Ha egy olyan vezérlőelemet tekint meg, mint a Button, látni fogja, hogy a vezérlő "Content" nevű tulajdonsága Objecttípusú. A Windows Formsban és a ASP.NET ez a tulajdonság általában sztring lenne, azonban ez korlátozza a gombba helyezhető tartalom típusát. A gomb tartalma lehet egyszerű sztring, összetett adatobjektum vagy teljes elemfa. Adatobjektumok esetén az adatsablont használja a rendszer egy megjelenítés létrehozásához.
Összefoglalás
A WPF dinamikus, adatvezérelt bemutatórendszerek létrehozását teszi lehetővé. A rendszer minden része úgy van kialakítva, hogy olyan tulajdonságkészleteken keresztül hozzon létre objektumokat, amelyek irányítják a viselkedést. Az adatkötés a rendszer alapvető része, és minden rétegben integrálva van.
A hagyományos alkalmazások létrehoznak egy kijelzőt, majd egyes adatokhoz kötődnek. A WPF-ben a vezérlő minden elemét, a megjelenítés minden aspektusát valamilyen adatkötés hozza létre. A gombon belül talált szöveg úgy jelenik meg, hogy létrehoz egy álló vezérlőt a gombon belül, és a kijelzőt a gomb tartalomtulajdonságához köti.
Amikor elkezdi a WPF-alapú alkalmazások fejlesztését, ismerősnek kell éreznie magát. A tulajdonságokat, az objektumokat és az adatkötéseket ugyanúgy állíthatja be, mint a Windows Forms vagy a ASP.NET. A WPF architektúrájának mélyebb vizsgálatával azt tapasztalhatja, hogy létezik lehetőség olyan sokkal gazdagabb alkalmazások létrehozására, amelyek alapvetően az adatokat kezelik az alkalmazás fő illesztőprogramjaként.
Lásd még
.NET Desktop feedback