Search This Blog

Friday, May 17, 2013

WPF Dependency Properties and Attached Properties Overview

Dependency Properties

WPF introduces a new type of property called a dependency property that is used throughout the platform to enable styling, automatic data binding, animation, and more

A dependency property depends on multiple providers for determining its value at any point in time. These providers could be an animation continuously changing its value, a parent element whose property value propagates down to its children, and so on. Arguably the biggest feature of a dependency property is its built-in ability to provide change notification.

Dependency properties add value on top of plain .NET properties:
  • Change notification
  • Property value inheritance
  • Support for multiple providers

Listing 3.3 demonstrates how Button effectively implements one of its dependency properties, called IsDefault.

LISTING 3.3 A Standard Dependency Property Implementation

public class Button : ButtonBase
{
// The dependency property
public static readonly DependencyProperty IsDefaultProperty;
static Button()
{
// Register the property
Button.IsDefaultProperty = DependencyProperty.Register(“IsDefault”,
typeof(bool), typeof(Button),
new FrameworkPropertyMetadata(false,
new PropertyChangedCallback(OnIsDefaultChanged)));
}
// A .NET property wrapper (optional)
public bool IsDefault
{
get { return (bool)GetValue(Button.IsDefaultProperty); }
set { SetValue(Button.IsDefaultProperty, value); }
}
// A property changed callback (optional)
private static void OnIsDefaultChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e) { … }
}


The static IsDefaultProperty field is the actual dependency property, represented by the
System.Windows.DependencyProperty class. By convention, all DependencyProperty fields are public, static, and have a Property suffix.

Dependency properties are usually created by calling the static DependencyProperty.Register method, which requires a name (IsDefault), a property type (bool), and the type of the class claiming to own the property (Button). Optionally (via different overloads of Register), you can pass metadata that customizes how the property is treated by WPF, as well as callbacks for handling property value changes, coercing values, and validating values. Button calls an overload of Register in its static constructor to give the dependency property a default value of false and to attach a delegate
for change notifications.

TIP:
Visual Studio has a snippet called propdp that automatically expands into a definition of a dependency property, which makes defining one much faster than doing all the typing yourself!


Dependency property implementation saves per-instance memory compared to a typical .NET property.

Change Notification:

Whenever the value of a dependency property changes, WPF can automatically trigger a number of actions, depending on the property’s metadata. These actions can be re-rendering the appropriate elements, updating the current layout, refreshing data bindings, and much more. One of the most interesting features enabled by this built-in change notification is property triggers, which enable you to perform your own.

With a property trigger, however, you can accomplish this same behaviour purely in XAML. The following concise Trigger object is just about all you need:

<Trigger Property=”IsMouseOver” Value=”True”>
<Setter Property=”Foreground” Value=”Blue”/>
</Trigger>

This trigger can act on Button’s IsMouseOver property, which becomes true at the same time the MouseEnter event is raised and false at the same time the MouseLeave event is raised. Note that you don’t have to worry about reverting Foreground to black when IsMouseOver changes to false. This is automatically done by WPF!

Property Value Inheritance

The term property value inheritance (or property inheritance for short) doesn’t refer to traditional object-oriented class-based inheritance but rather the flowing of property values down the element tree.

<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
Title=”About WPF 4 Unleashed” SizeToContent=”WidthAndHeight”
FontSize=30FontStyle=Italic
Background=”OrangeRed”>
<StackPanel>
<Label FontWeight=”Bold” FontSize=”20” Foreground=”White”>
WPF 4 Unleashed
</Label>
<Label>© 2010 SAMS Publishing</Label>
<Label>Installed Chapters:</Label>
<ListBox>
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel Orientation=”Horizontal” HorizontalAlignment=”Center”>
<Button MinWidth=”75” Margin=”10”>Help</Button>
<Button MinWidth=”75” Margin=”10”>OK</Button>
</StackPanel>
<StatusBar>You have successfully registered this product.</StatusBar>
</StackPanel>
</Window>


Support for Multiple Providers:

WPF contains many powerful mechanisms that independently attempt to set the value of dependency properties. Without a well-defined mechanism for handling these disparate property value providers, the system would be a bit chaotic, and property values could be unstable. Of course, as their name indicates, dependency properties were designed to depend on these providers in a consistent and orderly manner.

Figure 3.6 illustrates the five-step process that WPF runs each dependency property through in order to calculate its final value. This process happens automatically, thanks to the built-in change notification in dependency properties.

The pipeline for calculating the value of a dependency property. 
Determine Base Value à Evaluate (if an Expression) à Apply Animations à Coerce à Validate


TIP:

If you can’t figure out where a given dependency property is getting its current value, you can use the static DependencyPropertyHelper.GetValueSource method as a debugging aid. This returns a ValueSource structure that contains a few pieces of data: a BaseValueSource enumeration that reveals where the base value came from (step 1 in the process) and Boolean IsExpression, IsAnimated, and IsCoerced properties that reveal information about steps 2 through 4.

Attached Properties
An attached property is a special form of dependency property that can effectively be attached to arbitrary objects.

For the About dialog example, imagine that rather than setting FontSize and FontStyle for the entire Window (as is done in Listing 3.4), you would rather set them on the inner StackPanel so they are inherited only by the two Buttons. Moving the property attributes to the inner StackPanel element doesn’t work, however, because StackPanel doesn’t have any font-related properties of its own! Instead, you must use the FontSize and FontStyle attached properties that happen to be defined on a class called TextElement.

<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
Title=”About WPF 4 Unleashed” SizeToContent=”WidthAndHeight”
Background=”OrangeRed”>
<StackPanel>
<Label FontWeight=”Bold” FontSize=”20” Foreground=”White”>
WPF 4 Unleashed
</Label>
<Label>© 2010 SAMS Publishing</Label>
<Label>Installed Chapters:</Label>
<ListBox>
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel TextElement.FontSize=”30” TextElement.FontStyle=”Italic”
Orientation=”Horizontal” HorizontalAlignment=”Center”>
<Button MinWidth=”75” Margin=”10”>Help</Button>
<Button MinWidth=”75” Margin=”10”>OK</Button>
</StackPanel>
<StatusBar>You have successfully registered this product.</StatusBar>
</StackPanel>
</Window>

TextElement.FontSize and TextElement.FontStyle (rather than simply FontSize and FontStyle) must be used in the StackPanel element because StackPanel does not have these properties. When a XAML parser or compiler encounters this syntax, it requires that TextElement (sometimes called the attached property provider) have static methods called SetFontSize and SetFontStyle that can set the value accordingly.

Ref :  Adam Nathan (WPF EBook)
Post a Comment

Popular Posts