Dependency Properties in XAML for Windows 8 Apps
Most XAML objects derive from the base DependencyObject class. This is a special class that enables objects to participate in the dependency property system. The system enhances traditional properties and enables them to be inherited, to affect other classes, and to be manipulated in specified ways.
A dependency property is exposed internally as a static field that is registered with the dependency property system. By convention, the name of the field should end with Property. To register the property, you call the static Register method of the DependencyProperty type. To see this in action, open the DependencyProperties project. Take a look at the class called MyDependencyObject that inherits from DependencyObject:
public class MyDependencyObject : DependencyObject
The dependency property simply holds an integer. It is hosted using the static, read-only DependencyProperty like this:
public static readonly DependencyProperty MyNumberProperty = DependencyProperty.Register( "MyNumber", typeof (int), typeof (MyDependencyObject), new PropertyMetadata(2, OnMyNumberPropertyChange));
The property is named by the property system convention of ending with Property. The first parameter is the name of the property itself (without the suffix). The next parameter is the type of the property, which for this example is an integer. The third parameter is the type of the owner—the class that the dependency property depends on. The last parameter is optional and can provide a default value for the property and/or a method to call whenever the property changes.
The property specifies a method that is called when the property changes. The implementation of this method simply writes the new value to the debug console:
private static void OnMyNumberPropertyChange(DependencyObject d, DependencyPropertyChangedEventArgs e) { Debug.WriteLine("Property changed: {0}", e.NewValue); }
The MainPage.xaml file references this new dependency object. The XAML contains a Slider control. The Slider is used to manipulate values on the dependency object. The dependency object is defined in data context of the grid:
<Grid.DataContext> <local:MyDependencyObject/> </Grid.DataContext>
Beneath the DataContext for the Grid is the definition for the Slider control. It is bound to the MyNumber property of the dependency object. This binding means that the Slider will get an initial value from the referenced object. When the Slider is moved, the binding will update the target property because the binding is specified as a two-way binding:
<Slider Minimum="1" Maximum="100" Height="20" HorizontalAlignment="Stretch" Value="{Binding Path=MyNumber,Mode=TwoWay}" x:Name="Slider"/>
You learn more about data-binding later in this chapter.
Note - The DataContext is a special dependency property you learn more about in the data-binding section of this chapter. The property can be any object but is most often a class that derives from DependencyObject or implements INotifyPropertyChanged. Both of these options provide property change notification that the data-binding system uses to know when to update values. The DataContext is unique not only because it specifies the base object for data-binding instructions, but also because it is inherited. When you set the DataContext at the root Grid level, all child controls will also use the same DataContext unless they specifically override the value.
Although the dependency property system is used to register the dependency properties, they must be exposed to the runtime as common CLR properties. This is referred to as “backing” the properties. The value can be exposed as an ordinary property, but the getter and setter methods will reach out to the dependency property system to determine and/or set their value. Here is the backing code:
public int MyNumber { get { return (int) GetValue(MyNumberProperty); } set { SetValue(MyNumberProperty, value);} }
The GetValue and SetValue methods are provided by the base DependencyObject class. They are used to query the active values to expose to or update from the backing CLR property. Run the program in debug mode and move the Slider. You should see the new values appear in the debug output window as the result of the property-changed callback you defined.
Dependency properties offer several benefits over regular CLR properties. These include
- Property change notification—Dependency properties automatically inform the data-binding system when an underlying value changes.
- Property change callbacks—Developers can specify a delegate to receive callbacks when dependency properties change and therefore can react to changes outside of the data-binding system.
- Default values—Dependency properties can be defined with a default value that can be primitive or complex based on the type of property.
- Value precedence—There are multiple ways to influence the actual value of a dependency property including data-binding, styles definitions, XAML literals, and animations.
- Inheritance—Child elements can inherit the values of dependency properties from their parent elements.
All of these attributes make dependency properties ideal for the data-binding system that is built into XAML.
© Copyright Pearson Education. All rights reserved.