Személyes eszközök
Keresés

 

A InfoWiki wikiből


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.

A lap eredeti címe: „http://wiki.ektf.hu/wiki/Wpf:page80
Nézetek
nincs sb_18.222.125.171 cikk