Giriş

WPF ile uğraştıysanız farkında olmadan da olsa mutlaka Dependency propertyleri kullanmışsınızdır. Dependency propertyler normal .NET propertylerine oldukça benzemektedir, fakat Dependency propertyler konsept olarak çok daha güçlü ve komplekstir. Aralarındaki en önemli fark, normal bir .NET propertynin değeri sınıfta tanımlanmış private bir üyeden direkt olarak okunur.

Bir dependency propertynin değeri ise GetValue metodu çağrıldığında dinamik olarak çözümlenir.Bir dependency propertynin değerini set ettiğimizde bu nesnemizin bir alanında saklanmaz onun yerine DependencyObject temel sınıfı tarafından sağlanan bir dictionary de saklanmaktadır. Bildiğiniz gibi dictionary ler key ve value dan oluşmaktadır. Giriş key dediğimiz property ismi, value ise set etmek istediğimiz değeri tanımlamaktadır.

Dependency propertylerin avantajlarından en önemlileri dağıtık bellek kullanımını azaltma, değer kalıtımı ve property değişim bildirimi olarak sıralayabiliriz. Burada değer kalıtımı dediğimiz bir dependency propertye eriştiğimizde değeri, değer çözümleme stratejisi kullanılarak çözümlenir. Eğer lokal bir değer ayarlanmamışsa, dependency property bir değer buluncaya kadar mantıksal ağaçta bir üste yönlenir. Örneğin root elementte FontWeight’i ayarlarsak root element altındaki tüm TextBlock lara bu sitili override etmediğimiz sürece uygulanacaktır.

Değer Çözümleme Stratejisi

Dependency propertylere her erişimimizde değeri çözümlemek için yukardan aşağıya doğru öncelik sırasını takip eder.

1.Animation
2.Binding Expression
3.Local Value
4.Custom Style Trigger
5.Custom Template Trigger
6.Custom Style Setter
7.Default Style Trigger
8.Default Style Setter
9.Inherited Value
10.Default Value

Her WPF kontrolü static DependencyProperty sınıfına bazı dependency propertyleri kayıt eder. Bu propertylerin her biri tekil bir key'e (anahtar) ve geri dönüş ve varsayılan değer içeren metadataya sahiptir. Dependency property kullanmak isteyen tüm tipler Dependency Object sınıfından kalıtılmış olmak zorundadır. Bir dependency property'e onun .NET property wrapper üzerinden eriştiğimizde, değere erişmek için GetValue metodunu çağırır. Bu metod değer çözümleme stratejisini kullanarak uygun değeri döndürür.

Dependency Property Tanımlama
// Dependency Property        
public static readonly DependencyProperty HasTextProperty =  DependencyProperty.Register("HasText", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));  

//.NET Property wrapper       
public bool HasText  
{          
    get { return (bool)GetValue(HasTextProperty); }    
    set { SetValue(HasTextProperty, value); }      
}

Yukarıda tanımlanan dependency property ilk bakışta biraz karışık gelse de aslında çok kullanışlı ve güçlü bir yapısı vardır. Bir dependency property tanımlamak için isterseniz kısayol olarak code snippet kullanabilirsiniz. Kod tarafında propdp yazıp klavyeden iki kere Tab tuşuna bastığınızda otomatik olarak bir dependency property tanımlanır. Buradan önemli bir nokta isimlendirmeye dikkat ettiyseniz sonu Property ile bitmektedir. Bu tanımlama için gerekli bir koşuldur. İsimlendirmenin sonuna Property kelimesi konulması gerekmektedir HasTextProperty gibi.

Her dependency property değişikliği bildirme, değeri zorlama ve doğrulama için bir callback sağlar.

new FrameworkPropertyMetadata(false, OnHasTextPropertyChanged, OnCoerceHasTextProperty,OnValidateHasTextProperty);  
Change Notification Callback Metodu

HasTextProperty’ sinin değeri her değiştiğinde çağrılır. Yeni değer EventArgs üzerinden geçirilir.

private static void OnHasTextPropertyChanged(DependencyObject source,DependencyPropertyChangedEventArgs e) {       

     MainWindow control = source as MainWindow;         

     bool val= (bool)e.NewValue;                   

 }
Coerce Value Callback Metodu

Coerce value callback,exception fırlatmadan değerin belirlenen sınırlar içerisinde olmasını ayarlamamızı sağlar. Mesela bir progress bar’ı ele alırsak değerinin minimum 0 ve maksimum 100 arasında olması için zorlayabiliriz. Böylece exception fırlatmasını da engellemiş oluruz. Aşağıdaki örnek kodda eğer değerimiz 0 ile 100 arasında değilse değerimizi 0 olarak atıyoruz.

private static object OnCoerceHasTextProperty(DependencyObject sender, object data)  
 {       
     if (!((int)data >= 0 && (int)data<=100))            
     {          
          data = 0;  
     }        
     return data;       
}
Validation Callback Metodu

Bu metodumuzda ise set edilen değerin bizim dependency property nesnemizin tipinde olup olmadığını doğrulamamızı sağlar. Eğer false dönerse ArgumentException fırlatılır.

private static bool OnValidateHasTextProperty(object data)  
{    
    return data is bool; 
}

Gördüğünüz gibi dependency propertyleri kısaca bu şekilde tanımlayabiliriz. Normal .NET property’ler ile arasındaki farka gözattık ve bir dependency property tanımlama konusuna giriş yapmış olduk. Umarım yararlı bir yazı olmuştur.

About the Author