Monday, July 4, 2011

Dependency Properties in WPF


Dependency property is introduced with WPF and provides more features over normal property. It provides change notification and property inheritance (propagate value through element tree).  Dependency properties used in so many features of WPF like Data binding, Animation, Control Template, Styles etc.

Almost all objects in WPF are derived from Dependency Object base class. Please refer to my post WPF Class hierarchy to know more about it. You can create your own Dependency Property by deriving Dependency Object to you class. Dependency Object has two Major methods GetValue and SetValue. GetValue method used to get value from Dependency Property and SetValue method used to set value to Dependency Property. You can use DependencyProperty.Register method to register/create dependency property.

<Window x:Class="WpfApplication1.DependencyPropertyDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="DependencyPropertyDemo" Height="150" Width="250">
<Window.Resources>
    <local:DependencyPropertySample x:Key="MyDependency" />
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Label Content="Enter String:" Grid.Row="0"
           VerticalAlignment="Center" />
    <TextBox Text="{Binding Path=MyProperty, 
                            Source={StaticResource MyDependency}}"
             Name="MyTextblock" Height="25" Width="150" 
             HorizontalAlignment="Right" />
    <Button Name="MyButton" Content="Click Me!"
            Click="MyButton_Click" Height="25" 
            Width="150" Grid.Row="1" />
</Grid>
</Window>

public class DependencyPropertySample : DependencyObject
{
//Register Dependency Property
public static readonly DependencyProperty MyDependencyProperty = DependencyProperty.Register("MyProperty", typeof(string), typeof(DependencyPropertySample));

    public string MyProperty
    {
        get
        {
            return (string) GetValue(MyDependencyProperty);
        }
        set
        {
            SetValue(MyDependencyProperty, value);
        }
    }
}
public partial class DependencyPropertyDemo : Window
{
    public DependencyPropertyDemo()
    {
        InitializeComponent();
    }

    private void MyButton_Click(object sender, RoutedEventArgs e)
    {
        DependencyPropertySample dpSample = 
        TryFindResource("MyDependency") as DependencyPropertySample;
        MessageBox.Show(dpSample.MyProperty);
    }
}













You can also achieve data binding using code behind like this.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
    </Grid.RowDefinitions>
    <Label Content="Enter String:" Grid.Row="0"
            VerticalAlignment="Center" />
    <TextBox Text="" Name="MyTextblock" Height="25"
             Width="150" HorizontalAlignment="Right" />
</Grid>

public partial class DependencyPropertyDemo : Window
{
    public DependencyPropertyDemo()
    {
        InitializeComponent();
        DependencyPropertySample dpSample = 
             new DependencyPropertySample();
        dpSample.MyProperty = "Dependency Property";
        Binding mybinding = new Binding("MyProperty");
        mybinding.Mode = BindingMode.OneWay;
        mybinding.Source = dpSample;
        BindingOperations.SetBinding(MyTextblock, 
                    TextBox.TextProperty, mybinding);
    }
}













You can specify default value while registering dependency property. You also can specify different call backs with along with it like Property Changed Call Back, Coerce Value Call Back and Validate Value Call Back.

public static DependencyProperty MyDependencyProperty =
    DependencyProperty.Register("MyProperty"
             typeof(string),typeof(DependencyPropertySample),
    new PropertyMetadata("Test",
             new PropertyChangedCallback(OnMyPropertyChanged),
    new CoerceValueCallback(OnCoerceValue)),
    new ValidateValueCallback(OnValidateMyProperty));

public string MyProperty
{
    get
    {
        return (string) GetValue(MyDependencyProperty);
    }
    set
    {
        SetValue(MyDependencyProperty, value);
    }
}
public static void OnMyPropertyChanged( DependencyObject dObject, 
          DependencyPropertyChangedEventArgs e)
{
    MessageBox.Show(e.NewValue.ToString());
}
public static string OnCoerceValue(DependencyObject dObject, object val)
{
    if (val.ToString().CompareTo("Test") == 1)
    {
        return val.ToString();
    }
    return string.Empty;
}
public static bool OnValidateMyProperty(object myObj)
{
    if (myObj.ToString() == string.Empty)
        return false;
    return true;
}

On Value Change CallBack – You can execute some logic /code when dependency properties value changed

On Coerce Value CallBack – You can reset or specify some exact value when the value of your Dependency Property goes outside the boundaries. You can use this call back to specify lower and upper limit of your dependency property.

On Validate Value CallBack – you can check or validate value of your dependency property inside this call back. This call back returns Boolean value.

Clear Dependency Property Local Value


You can clear dependency property local value using ClearValue method. 

dpSample.ClearValue(DependencyPropertySample.MyDependencyProperty);


Read-only Dependency Properties


Some time you need property which returns state of your control or object. In WPF there are certain read-only dependency properties available like IsPressed, IsMouseOver etc. The read only dependency properties can be defined using DependencyProperty.RegisterReadOnly.


//Register Dependency Key
public static DependencyPropertyKey MyReadonlyDependencyPropertyKey =
    DependencyProperty.RegisterReadOnly("MyReadonlyProperty"typeof(string), typeof(DependencyPropertySample),
    new PropertyMetadata("Test",new PropertyChangedCallback(OnMyPropertyChanged)));

//Register Dependency Property using Dependency Key
public static readonly DependencyProperty MyReadonlyDependencyProperty = MyReadonlyDependencyPropertyKey.DependencyProperty;

//Property
public string MyReadonlyProperty
{
    get
    {
        return (string)GetValue(MyReadonlyDependencyProperty);
    }
    private set
    {
        SetValue(MyReadonlyDependencyProperty, value);
    }
}

You might also like
Introduction to WPF
WPF Architecture
WPF Class Hierarchy

6 comments:

  1. Wow what a nice post. I like it.


    Thanks for more info.........







    ZVN Properties Inc

    ReplyDelete
  2. Thank you very much this what i am looking for.

    ReplyDelete
  3. This Blog helped me a lot.Please share article WPF Threading ,threading type and background worker process and locks.

    ReplyDelete