Twitter

Facebook

Umbraco Certified

RAR Recommended

Twitter

Thu 17 May 12 @ 7:06JetBrains dotPeek 1.0 has just been released http://t.co/q0toNbzY

Wed 16 May 12 @ 8:53Grew up in the 1980's? Take a trip down memory lane http://t.co/nFPqtLtH #1980s #memories

Tue 15 May 12 @ 8:30What a cool idea for a piggy bank http://t.co/IN08jLi2

Follow Us On Twitter

nopCommerce Solution Provider

Microsoft Partner Network

Archive

View All

WPF User Controls: Turn Your User Control Into A Data Binding Target

Tuesday, September 20, 2011

When we create user controls we will usually want to bind some data to them. In other words we want our control to be a data binding target associated with a data binding source. Typically a source is an object from our data model, and we want to associate it with a UI element so that values from our object can be displayed and updated automatically. The UI element is the target in the data binding scenario - this is our user control.

For example we might declare a data binding association like this:

<Controls:HourMinutePicker HourMinute="{Binding Task.ScheduledHourMin, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" HorizontalAlignment="Right" Margin="0,252,314,0" x:Name="hourMinutePicker1" VerticalAlignment="Top" />

In this case we have embedded a user control of type "HourMinutePicker" in a parent dialog and bound it as a target to the "ScheduledHourMin" property of an object named "Task". Our current task's scheduling data is now displayed in our user control, and if the user types into the control fields then the task object's values (hour and minute) are automatically updated.

Dependency Properties Underlie Data Binding Targets

In order for a user control to implement the target side of data binding, it must support "dependency properties". WPF uses these properties when it manages the data flow between sources and targets during data binding. Dependency properties are in effect cached by the framework and looked up by name when the property values are fetched or updated. Dependency properties can be mapped to regular properties so that the source in the binding appears to be mapping to a simple public property in the target. In the example above we are binding the HourMinute property of the target to the task object's property that controls scheduling. The HourMinute property in our user control is a regular public property, but it is associated with a dependency property. This association is not apparent in the xaml.

Dependency properties have attributes that control the direction of binding (e.g. one-way, two-way etc.), and also callbacks so that your code can participate in data updates that arise from data binding.

Creating Dependency Properties

Inheritance

Classes that support dependency properties must derive from DependencyObject, either by direct subclassing or via an existing subclass. All UI elements in WPF already derive from DependencyObject, including class UserControl, so your user control will already be of the right type.

  public partial class HourMinutePicker :UserControl

Dependency Property

You will need to declare a dependency property for each regular property that you want to make available for data binding. The declaration of a dependency property is a static declaration  using the "Register" method of DependencyProperty. It states the name of the associated regular property and its data type (among other things). In our example:

public static DependencyProperty HourMinuteProperty = DependencyProperty.Register(
            "HourMinute", typeof(DateTime), typeof(HourMinutePicker), 
            new PropertyMetadata(OnHourMinChanged));

Public Property

The data binding is established by referencing a regular public property in the user control. So we start by declaring a normal public property, with a name and type that match the dependency property declaration:

public DateTime HourMinute
{
    get
    {
    }
    set
    {
   }
}

An association is made between the normal property and the dependency property by calling special methods within the get and set (in other words the regular property wraps the dependency property):

public DateTime HourMinute
{
    get    {return (DateTime) GetValue(HourMinuteProperty);}
    set    { SetValue(HourMinuteProperty, value); }
}

Callback

The framework is not guaranteed to call the setter of the public property when updates occur as part of the binding (for example when the user types into the user control). However, you can specify a callback that will be triggered when the value is updated. In this example, the callback is the last parameter in the registration of the dependency property:

 

public static DependencyProperty HourMinuteProperty = DependencyProperty.Register(
    "HourMinute", typeof(DateTime), typeof(HourMinutePicker), 
    new PropertyMetadata(OnHourMinChanged));

 

The callback in this case is a method called "OnHourMinChanged". This must be a static method in the user control. It is passed two parameters. One is the instance of the user control that has been updated, and the other contains new and old values for the property in question. You can use this information to call an instance method:

static void OnHourMinChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    if (obj != null && obj is HourMinutePicker)
    {
        // Extract the instance and call the appropriate method
        (obj as HourMinutePicker).UpdateTime(e);
    }
}

The UpdateTime method is an instance method that can take action such as updating a local variable etc:

private void  UpdateTime(DependencyPropertyChangedEventArgs e)
{
    _hourMinute = (DateTime) e.NewValue;
}

Complete Code

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace FtpSync.Controls
{
   public partial class HourMinutePicker : UserControl   {
        public static DependencyProperty HourMinuteProperty = DependencyProperty.Register(
            "HourMinute", typeof(DateTime), typeof(HourMinutePicker), 
            new PropertyMetadata(OnHourMinChanged));

       private DateTime _hourMinute = new DateTime(1900, 1, 1);

       static void OnHourMinChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj != null && obj is HourMinutePicker)
            {
               (obj as HourMinutePicker).UpdateTime(e);
            }
        }

       private void  UpdateTime(DependencyPropertyChangedEventArgs e)
        {
            _hourMinute = (DateTime) e.NewValue;
        }

       public DateTime HourMinute
        {
            get
            {
               return (DateTime) GetValue(HourMinuteProperty);
            }
            set
            {
               SetValue(HourMinuteProperty, value);
            }
        }

       public HourMinutePicker()
        {
            InitializeComponent();
        }
 }
}

Summary of Key Points

To allow  your user control to participate as a target in data binding, you will need to expose properties that can be mapped to equivalent properties in the source element of the binding. These user control properties will be simple public properties in the user control, but the internals of their getters and setters will call corresponding dependency properties. These dependency properties will be registered using the static Register call, which can also define callbacks so that your code knows when the framework has made an update as a a result of data binding.

http://www.wpftutorial.net/DependencyProperties.html

http://dev-for-fun.blogspot.com/2008/06/wpf-example-create-usercontrol-and.html