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