WPF introduces a new type of property called a dependency property, used throughout the platform to enable styling, automatic data binding, animation, and more. Definition of Dependency Properties on MSDN
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 trickles down to its children, and so on. Arguably the biggest feature of a dependency property is its built-in ability to provide change notification. The motivation for adding such intelligence to properties is to enable rich functionality directly from declarative markup.
Below is the demonstration of how Button effectively implements one of its dependency properties which is called IsDefault.
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.
So one of the first things I thought was weird about the definition of a dependency property is that it is a static. This property needs to store info relevant to a particular instance of a class, how is it going to do that if it is static?
As you read more about them, you will realized that a dependency property definition was exactly that – a definition. You are essentially saying that class A will have a property B – and it makes sense that that definition would be static. The actual storage of a value for a dependency property is deep inside the WPF property system – you never have to worry about it.
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.
Finally, the traditional .NET property called IsDefault implements its accessors by calling GetValue and SetValue methods inherited from System.Windows.DependencyObject, a low-level base class from which all classes with dependency properties must derive. GetValue returns the last value passed to SetValue or, if SetValue has never been called, the default value registered with the property.
So at first glance, all the properties on the new WPF controls seem to be regular old properties. But don’t be fooled – this is often just a simple wrapper around a dependency property.
The IsDefault .NET property (sometimes called a property wrapper) is not strictly necessary; consumers of Button could always directly call the GetValue/SetValue methods because they are exposed publicly. But the .NET property makes programmatic reading and writing of the property much more natural for consumers, and it enables the property to be set via XAML.
GetValue and SetValue internally use an efficient sparse storage system and because IsDefaultProperty is a static field (rather than an instance field), the dependency property implementation saves per-instance memory compared to a typical .NET property. If all the properties on WPF controls were wrappers around instance fields (as most .NET properties are), they would consume a significant amount of memory because of all the local data attached to each instance. The benefits of the dependency property implementation extend to more than just
memory usage, however. It centralizes and standardizes a fair amount of code that property implementers would have to write to check thread access, prompt the containing element to be re-rendered, and so on.
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 custom actions when a property value changes without writing any procedural code.
For example, imagine that you want the text in each Button to turn blue when the mouse pointer hovers over it. Without property triggers,you can attach two event handlers to each Button, one for its MouseEnter event and one
for its MouseLeave event:
<Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave” MinWidth=”75” Margin=”10”>Help</Button> <Button MouseEnter=”Button_MouseEnter” MouseLeave=”Button_MouseLeave” MinWidth=”75” Margin=”10”>OK</Button>
These two handlers could be implemented in a C# code-behind file as follows:
// Change the foreground to blue when the mouse enters the button void Button_MouseEnter(object sender, MouseEventArgs e) { Button b = sender as Button; if (b != null) b.Foreground = Brushes.Blue; } // Restore the foreground to black when the mouse exits the button void Button_MouseLeave(object sender, MouseEventArgs e) { Button b = sender as Button; if (b != null) b.Foreground = Brushes.Black; }
With a property trigger, however, you can accomplish this same behavior 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 upon 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! You could apply the preceding Trigger to a Button by wrapping it in a few intermediate XML elements as follows:
<Button MinWidth=”75” Margin=”10”> <Button.Style> <Style TargetType=”{x:Type Button}”> <Style.Triggers> <Trigger Property=”IsMouseOver” Value=”True”> <Setter Property=”Foreground” Value=”Blue”/> </Trigger> </Style.Triggers> </Style> </Button.Style> OK </Button>
Three type of triggers are available in WPF
Property Triggers : As mentioned above
A data trigger is a form of property trigger that works for all .NET properties (not just dependency properties)
An event trigger enables you to declaratively specify actions to take when a routed event. Event triggers always involve working with animations or sounds
Property Value Inheritance
The term property value inheritance or property inheritance doesn’t refer to traditional object oriented class based inheritance, but rather the flowing of property values down the element tree.
Example :
<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” Title=”Property Inheritance sample” SizeToContent=”WidthAndHeight” FontSize=”30” FontStyle=”Italic” Background=”OrangeRed”> <StackPanel> <Label FontWeight=”Bold” FontSize=”20” Foreground=”White”> WPF Property Inheritance </Label> <Label>Rajneesh</Label> <Label>Tech</Label> <ListBox> <ListBoxItem>.Net</ListBoxItem> <ListBoxItem>C#</ListBoxItem> </ListBox> <StackPanel Orientation=”Horizontal” HorizontalAlignment=”Center”> <Button MinWidth=”75” Margin=”10”>Cancel</Button> <Button MinWidth=”75” Margin=”10”>OK</Button> </StackPanel> <StatusBar>You have successfully created property inheritance</StatusBar> </StackPanel> </Window>
Note : Window automatically resizes to fit all the content thanks to its slick SizeToContent setting!
In above example we are explicitly setting window FontSize and FontStyle dependency properties.
For the most part, these two settings flow all the way down the tree and are inherited by children. This affects even the Buttons and ListBoxItems, which are three levels down the logical tree. The first Label’s FontSize does not change because it is explicitly marked with a FontSize of 20, overriding the inherited value of 30.
Note : Internally, dependency properties can opt in to inheritance by passing FrameworkPropertyMetadataOptions. Inherits to DependencyProperty.Register
Support for Multiple Providers
WPF contains many powerful mechanisms that independently attempt to set the value of dependency properties.
Attached Properties
An attached property is a special form of dependency property that can effectively be attached to arbitrary objects.
Imagine that rather than setting FontSize and FontStyle for the entire Window (in above example), you would rather set them on the inner StackPanel so they are inherited only by the two Buttons. But 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.
<StackPanel TextElement.FontSize=”30” TextElement.FontStyle=”Italic” Orientation=”Horizontal” HorizontalAlignment=”Center”> <Button MinWidth=”75” Margin=”10”>Cancel</Button> <Button MinWidth=”75” Margin=”10”>OK</Button> </StackPanel>
Just like previous technologies such as Windows Forms, many classes in WPF define a Tag property (of type System.Object) intended for storing arbitrary custom data with each instance. But attached properties are a more powerful and flexible mechanism for attaching custom data to any object deriving from DependencyObject. It’s often overlooked that attached properties enable you to effectively add custom data to instances of sealed classes.
*Beginners : I would like to recommended WPF fundamental tutorials by Christian Moser at http://www.wpftutorial.net