User Tools

Site Tools


notes:uwp:dependencyproperties

Dependency Properties in XAML

  • Dependency properties can be the targets of styles, bindings, and animations. This means that you can only style and animate dependency properties.
  • Dependency properties have built-in ability to provide change notifications and property value inheritance. Keep in mind that not every dependency property participates in property value inheritance.
  • Classes that participate in the dependency property system must derive from the DependencyObject class.
  • Dependency properties are always declared as static and readonly.
  • The getters and setters can be provided for convenient access to the dependency property (a “wrapper property”).

Do not include any logic in .NET property wrappers besides GetValue/SetValue calls. Property wrappers are bypassed at runtime when setting dependency properties in XAML.

  • Visual Studio snippet 'propdb' expands into a definition of a dependency property.
  • Visual Studio snippet 'propa' expands into a definition of an attached property.

The property value providers in order from highest to lowest precedence:

  • Active animations
  • Local value
  • Template properties
  • Style setters
  • Property value inheritance
  • Default value

DependencyProperty

A few examples of dependency properties defined in a custom OwnerClass:

// An integer dependency property with an initial value 0.
public static readonly DependencyProperty CounterProperty =
    DependencyProperty.Register("Counter", typeof(int), typeof(OwnerClass), new PropertyMetadata(0));
 
// A .NET property wrapper (optional). The GetValue and SetValue methods are inherited from DependencyObject.
public int Counter
{
    get { return (int)GetValue(CounterProperty); }
    set { SetValue(CounterProperty, value); }
}
// A Boolean dependency property with an initial value true.
public static readonly DependencyProperty IsEnabledProperty =
    DependencyProperty.Register("IsEnabled", typeof(bool), typeof(OwnerClass), new PropertyMetadata(true));
 
public bool IsEnabled
{
    get { return (bool)GetValue(IsEnabledProperty); }
    set { SetValue(IsEnabledProperty, value); }
}
// A string dependency property with an initial value "".
public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register("Title", typeof(string), typeof(OwnerClass), new PropertyMetadata(""));
 
public string Title
{
    get { return (string)GetValue(TitleProperty); }
    set { SetValue(TitleProperty, value); }
}

Attached Properties

Example: Define an attached property Row on a class CustomGrid:

namespace TestApp
{
    public class CustomGrid : DependencyObject
    {
        public static readonly DependencyProperty RowProperty =
            DependencyProperty.RegisterAttached("Row", typeof(int), typeof(CustomGrid), new PropertyMetadata(0));
 
        // Setting attached properties in XAML relies on the presence of the static Set method 
        // such as SetRow in this example.
        public static void SetRow(UIElement element, int value)
        {
            element.SetValue(RowProperty, value);
        }
 
        public static int GetRow(UIElement element)
        {
            return (int)element.GetValue(RowProperty);
        }
    }
}    

Usage:

<Page x:Class="TestApp.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:TestApp">
 
    <Grid>
        <Image local:CustomGrid.Row="1" ... />
    </Grid>
</Page>

Links:

You can also use attached properties as an extensibility mechanism. They enable you to add properties to instances of other classes/elements even if they are sealed.

Example: Attch the Tag property to the PlaneProjection element. The PlaneProjection element does not have a Tag property because it is not a FrameworkElement.

PlaneProjection proj = new PlaneProjection();
proj.SetValue(FrameworkElement.TagProperty, "some data"); // call DependencyObject.SetValue directly

PropertyChangedCallback

Example: Handle property value changes. We define a Radius dependency property with a PropertyChanged callback. The callback specifies to invoke the OnRadiusChanged event every time the value of the dependency property changes:

// OnRadiusChanged is a delegate for change notifications.
public static readonly DependencyProperty RadiusProperty =
    DependencyProperty.Register("Radius", typeof(double), typeof(OwnerClass),
        new PropertyMetadata(200.0, new PropertyChangedCallback(OnRadiusChanged)));
 
// wrapper property
public double Radius
{
    get { return (double)GetValue(RadiusProperty); }
    set { SetValue(RadiusProperty, value); }
}
 
// callback method
// DependencyPropertyChangedEventArgs properties:
// - Property - the property that has been changed
// - OldValue
// - NewValue
private static void OnRadiusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    // The obj parameter is an instance of the OwnerClass. You may use it to call any instance methods.
    OwnerClass owner = obj as OwnerClass;
 
    // ...
}

ClearValue

Example: Clear a locally set property value using the DependencyObject's ClearValue method. You may need to do that if you want an element (here: a TextBlock) to inherit a value from a lower precedence property value provider:

// TextBlock1 is a TextBlock element.
// TextBlock.FontSizeProperty is the static DependencyProperty field.
TextBlock1.ClearValue(TextBlock.FontSizeProperty);
notes/uwp/dependencyproperties.txt · Last modified: 2016/12/22 by admin