Sistemul de proprietati cu getter si setter din .NET a reprezentat o imbunatatire semnificativa asupra modului de lucru din Visual C++ cu clase si obiecte, prin simplul motiv ca ne permit executarea de cod in momentul schimbarii, respectiv citirii valorii unui camp intern al unei clase. Doua utilizari clasice sunt urmatoarele:
- Redesenarea unei ferestre in momentul shimbarii unei proprietati (Width, Height, Background etc.)
- Validarea valorii unui camp al unei clase in momentul setarii lui.
Practic, proprietatile din .NET doar sunt o metoda excelenta de a notifica obiectul a carui camp il schimbam. Dependency Properties preiau aceasta idee si o duc mai departe, prin notificarea intregului engine WPF de modificarea unei proprietati.
Pentru a intelege modelul de dependency properties, este necesara intelegerea conceptului de arbore vizual din WPF. Practic, intreaga interfata este organizata intern sub forma unei structuri arborescente (asemanatoare DOM-ului in cazul html). Controalele in Silverlight sunt compuse practic din forme geometrice (curbe, linii) si containere, astfel intreg arborele este compus in general din containere si geometrie. Spre deosebire de WindowsForms, structura geometrica interna a unui control este 100% editabila prin Templates, deci in consecinta putem avea controale care arata total diferit de aspectul default. Sa consideram urmatorul exemplu: Un grid contine un buton, ce la randul lui contine o imagine si text (unul dintre feature-urile excelente a le lui Silverlight este posibilitatea ca niste controale uzuale gen Button, Combo pot sa contina alte controale ca si content). In momentul in care Width-ul butonului este schimbat programatic, el notifica atat controlul parinte cat si controalele continute ce se vor redimensiona.
Regula de baza este ca de obicei valoarea pe care o punem intr-un DP, nu este si valoarea pe care o vom gasi la interogare. De exemplu, chiar daca setam Width-ul butonului la o anumita valoare, ea poate fi constransa de dimensiunea maxima a gridului, sau de o serie de alti factori. Practic denumirea de DependencyProperty vine chiar de la acest lucru – faptul ca valoarea proprietatii depinde de un numar mare de factori. Printre factorii care actioneaza asupra valorii unui DP, in ordinea prioritatii se numara:
- Sistem intern de coercitie a valorii
- Animatii active ce actioneaza asupra proprietatii respective
- Valoarea locala setata
- Stilul definit asupra controlului
- Sablonul controlului respectiv
- Tema
- Mostenire
- Valoare default a proprietatii
Valoarea pe care o punem in campul respectiv nu este decat pe locul trei in lista noastra. Practic un DP, nu are o valoare proprie, ci mai degraba una calculata si validata. Pentru ca un obiect sa poata sa suporte Dependency Properties, el trebuie sa fie derivat din clasa DependencyObject.
public class MyClass: DependencyObject
{
public static readonly DependencyProperty
MyDPProperty =
DependencyProperty.Register("MyDP", typeof(string),
typeof(double), new PropertyMetadata(MyClass.MyDPPValueChanged));
public string MyDP
{
get { return (string)GetValue(MyDPProperty); }
set { SetValue(MyDPProperty, value); }
}
private static void MyDPPValueChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
MyClass myClass = (MyClass)d;
// modificari pe instanta obtinuta
}
}
Pasii sunt urmatorii:
-
Clasa care contine DP-ul trebuie sa fie derivata din DependencyObject.
-
In aceasta, se creeaza o proprietate statica, care deriveaza din DependencyProperty, si are numele dorit al proprietatii noastre plus sufixul Property.
-
Proprietatea este inregistrata in sistemul WPF cu ajutorul metodei statice DependencyProperty.Register().
-
Pentru o folosire mai usoara, proprietatea statica este impachetata. In getter si setter se folosesc metodele GetValue si SetValue mostenite din DependencyObject. Atentie! Compilatorul elimina getterul si setterul, si acceseaza direct proprietatea statica. Orice cod inclus in setter este eliminat.
-
Prelucrarea datelor in caz de modificarea proprietatii se face in handler (in cazul nostru MyDPPValueChanged).