A InfoWiki wikiből
(Új oldal, tartalma: „<cim cim3="A tartalom (Content)" cim2="Windows Presentation Foundation" cim1="Windows Forms Reloaded" prev="wpf:page70" next="wpf:page90" kep="hz_csik.png"...”) |
Aktuális változat (2009. június 24., 18:25) (lapforrás) (uploaded) |
||
1. sor: | 1. sor: | ||
- | <cim | + | <cim cim2="Windows Presentation Foundation" cim3="Windows Forms Reloaded" prev="" back="Kezdolap" next="" kep="hz_csik.png" szerzo="hz|Hernyák Zoltán"/> |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | /> | + | |
= WPF / Dependency Property = | = WPF / Dependency Property = |
Aktuális változat
WPF / Dependency Property
Amennyiben egy form tartalmaz egymásba ágyazott elemeket (panel, amelyeken újabb panelek, grid-ek vannak), akkor kialakul egy faszerkezet, melynek gyökere természetesen maga az ablak.
A fa szintjein lévő objektumok alapértelmezett módon bizonyos property-k értékeit átvesznek az őseiktől (öröklődés). Ez mindaddig így is van, amíg egy adott elem adott property-jét explicit módon be nem állítjuk. Ez esetben ezen explicit érték természetesen nem íródik felül később automatikusan, ha a fában felette lévő elemek ide vonatkozó property-értékét megváltoztatjuk. A prioritások az alábbiak:
- default érték
- ősétől örökölt érték
- explicit módon beállított érték
Persze a helyzet bonyolultabb, ha a fában valamely szinten lévő elemnek nincs is adott property-je. Pl. egy GRID-nek nincs FontSize property-je. Így ha egy Panel -> Grid -> Button a felállás, és a panel-nek átállítjuk a FontSize propertyjének értékét, akkor az hogy juthatna el a Button-hoz?
A Dependency Property (függőségi jellemző) olyan property, amelynek értéke dinamikusan van számolva, és aktuális értéke függhet más objektumok valamely property értékétől, külső behatásoktól.
Egyszerű property:
private double fntsize = 11; public double FontSize { get { return fntsize; } set { fntsize = value; ... } }
Ugyanez dependency property-vel:
public class Control: FrameworkElement { ... public static readonly DependencyProperty FontSizeProperty; ... static public Control() { FontSizeProperty = DependencyProperty.Register("FontSize", typeof(double), typeof(Control)); ... } }
Ezzel jeleztük, hogy a Control példányoknak lesz FontSize property-jük. A property működése a dependency property-k működésének szokásos sémáin alapul. Az érték tárolását nem egy fizikailag is létező mező végzi a példány belsejében, hanem a rendszer végzi (valahogy). Nem jellemző, hogy tényleges adattárolás történne (bár az sem kizárt), inkább olvasáskor meghatározza az aktuális értéket (valahogy).
Persze ezen property-t egy kicsit lehet finomítani is meta-adatok átadásával:
public class Control: FrameworkElement { ... public static readonly DependencyProperty FontSizeProperty; ... static Control() { FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(); metadata.DefaultValue = 11; metadata.AffectsMeasure = true; metadata.Inherits = true; metadata.IsDataBindingAllowed = true; metadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; FontSizeProperty = DependencyProperty.Register("FontSize", typeof(double), typeof(Control), metadata, ValidateFontSize); } static bool ValidateFontSize(object obj) { double dFontSize = (double) obj; return dFontSize > 0 && dFontSize <= 35791; } ... }
A dolgok mögött egy DependencyObject példány áll. Ő képviseli a háttérben a property-nket. Neki van SetValue() és GetValue() metódusai. A GetValue() feladata, hogy mindaddig, amíg nem állítottunk be explicit értéket, addiga defValue-t adja meg kérdéskor. A SetValue() dolga, hogy amennyiben valaki módosítaná az értéket, a validate függvényt aktivizálja, majd a válaszától függően kivételt dobjon. Ha a válasz elfogadó, az AffectMeasure miatt kalkuláltassa újra a Control méreteit. Majd adja az új értéket tovább minden gyermekének. A gyermekekben ugyanez a mechanizmust fog aktivizálódni.
Olyan property-ket kell dependency stilusúvá tenni, amelyek a vizuális fában lejjebb lévő gyermekek felé várhatóan továbbadandóak. Amelyek a sajátjaink, azokat a hagyományos OOP technikával is lekódolhatóak.
WPF / Routed Events
Három alapvető input van:
- billentyűzet esemény
- egér esemény
- stylus esemény (elsősorban tabletpc-ken)
Az esemény forrása mindíg az az objektum, amelyik épp a 'fókuszt' birtokolta, amikor az esemény bekövetkezett. Ez az objektum látható, és legfelelül van éppen.
Korábban, ha valaki felülírt egy OnMouseDown metódust, meg kellett hívni a felülírtat az ősosztályban, hogy ne szakítsa meg a feldolgozóláncot. Valamely ősben ugyanis volt egy beépített hívás, amely az OnClick eseménykezelőre feliratkozott callback függvényeket meghívta (ha volt egyáltalán feliratkozott).
A WPF-ben ha felülírunk egy OnMouseDown-t, nem kell az ős OnMouseDown-ját hívni, mivel az eseménykezelést alapjaiban cserélték ki, és e miatt erre már nincs szükség.
Amikor egy esemény történik, első fázisban tunnels down, vagyis a vizuális fában a gyökértől (maga egy form) elkezd lefelé szivárogni a fókuszt birtokló objektum felé. Második fázisban bubbling up lesz, vagyis elkezd majd felfelé emelkedni ugyanebben a fában, ugyanezen útvonalon.
Tunnels down fázisban bármely útba ejtett objektum elkaphatja a PreviewMouseDown esemény kapcsán. Amennyiben a Handled-t true-re állítja, ezzel meg is szakítja az esemény további feldolgozását. A Handeld-t false-on hagyva az tovább folytatja útját lefele. Ebben a fázisban PreviewMouseDown eseménnyel lehet találkozni. Felfelé már hagyományos MouseDown esemény lesz, aki felfelé emelkedik. Ennél jelentősebb változás pl a Button esetén, ha lefele egy PreviewKeyUp vándorol, amit a button feldolgoz, és átcserlés Click eseményre, mivel ezt ő így interpretálta.
Mouse capture kapcsán telepíteni kell egy LostMouseCapture eseményt, amely meghívódik, amikor a Windows úgy dönt - elveszi az egeret tőlünk, vagy a program egy Mouse.Capture(null)-t hív, jelezvén hogy nincs már rá tovább szüksége.