Pages

Sunday, 30 January 2011

Dependency Property

Definition:
Dependency property is a new type of property which can be used with dependency objects, to enable styling, data binding or animation. To define your own dependency property you have to register your new property using DependencyProperty.Register(...) method and optionally you can create FrameworkPropertyMetadata object where you can specify property characteristics.

Example:

   1:   public partial class MinMaxControl : Control
   2:      {
   3:          public static readonly DependencyProperty MinProperty = 
   4:              DependencyProperty.Register("Min", typeof(int), typeof(MinMaxControl),
   5:              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
   6:                  HandleMinValueChanged, CoerceMinValue), ValidateMinValue);
   7:          public static readonly DependencyProperty MaxProperty = 
   8:              DependencyProperty.Register("Max", typeof(int), typeof(MinMaxControl),
   9:              new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
  10:                  HandleMaxValueChanged, CoerceMaxValue), ValidateMaxValue);
  11:   
  12:          static MinMaxControl()
  13:          {
  14:              DefaultStyleKeyProperty.OverrideMetadata(typeof(MinMaxControl), new FrameworkPropertyMetadata(typeof(MinMaxControl)));
  15:          }
  16:   
  17:          public int Min
  18:          {
  19:              get { return (int)GetValue(MinMaxControl.MinProperty); }
  20:              set { SetValue(MinMaxControl.MinProperty, value); }
  21:          }
  22:   
  23:          public int Max
  24:          {
  25:              get { return (int)GetValue(MinMaxControl.MaxProperty); }
  26:              set { SetValue(MinMaxControl.MaxProperty, value); }
  27:          }
  28:   
  29:          private static void HandleMinValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  30:          {
  31:   
  32:          }
  33:   
  34:          private static void HandleMaxValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  35:          {
  36:   
  37:          }
  38:   
  39:          private static object CoerceMinValue(DependencyObject d, object value)
  40:          {
  41:              var control = d as MinMaxControl;
  42:              if (control != null)
  43:              {
  44:                  if ((int)value > control.Max)
  45:                      return control.Max;
  46:              }
  47:              return value;
  48:          }
  49:   
  50:          private static object CoerceMaxValue(DependencyObject d, object value)
  51:          {
  52:              var control = d as MinMaxControl;
  53:              if (control != null)
  54:              {
  55:                  if ((int)value < control.Min)
  56:                      return control.Min;
  57:              }
  58:              return value;
  59:          }
  60:   
  61:          private static bool ValidateMinValue(object value)
  62:          {
  63:              if ((int)value < 0)
  64:                  return false;
  65:              return true;
  66:          }
  67:   
  68:          private static bool ValidateMaxValue(object value)
  69:          {
  70:              if ((int)value < 0)
  71:                  return false;
  72:              return true;
  73:          }
  74:      }

When you specify a Dependency Property you have to include:
  • property name,
  • property type,
  • property owner type,
  • optionally, a FrameworkPropertyMetadata object,
  • optionally, a validation callback
When you specify a property you have to be aware that it may be set incorrectly. Dependency property has set of tools which you can use to protect yourself against incorrect values: ValidateValueCallback and CoerceValueCallback. Previously mentioned callbacks are executed in a particular order as follows:
  1. ValidateValueCallback - does not have any knowledge about other dependency properties so the input value can be validated against some predefined conditions only, 
  2. CoerceValueCallback - has access to a control so the value can be modified based on other properties, 
  3. PropertyValueChangedCallback - the last step of the whole process, can force coercion on other dependency properties if necessary.
If you want/have to change a dependency property metadata and you do not have a direct access to the property you can achieve it using OverrideMetadata method:

   1:   MinProperty.OverrideMetadata(typeof(ModifiedMinMaxControl), new FrameworkPropertyMetadata(123, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

Useful links:
Source code: DependencyProperyCoercionValidation.zip

No comments:

Post a Comment