DependencyObject provides WPF property system. The WPF system needs the needs the properties to have a richer set of services like change notification is required for triggers and data binding. So apart from Change Notifications we also need Default Values, Type Coercion, Data Binding, Attached Properties, Validation, Inheritance down the Visual Tree and Styling to be available for the properties. It’s not feasible to implement all these features to a property every time we use it, so it’s really helpful to have these features already present in the properties. DependencyObject is the base type of most of the types we work in WPF and hence they already have all these features of the DependencyObject.
To use a dependency Property we need to do the following things.
- Derive from DependencyObject
- Register the DependencyProperty by passing the name of the property, the type of the property, the type that owns the property and the metadata for the property.
- As per convention make it public static and readonly.
- The assessors for the property become one liner by getting and setting the dependency property.
The dependency object that gets returned by register is used to identify the property.
The metadata can define the default value of the property, callbacks from the receiving property change notification, performing value Coercion.
The Change Notification handler is passed as a part of the metadata. WPF will call this handler anytime the property value changes. Only the property changed directly will go through the set assessor. The changes originating from styles, data binding, triggers, animation will not go through the set assessor. So the callback is useful these changes. So we can write the static callback function as it goes through the static property.
These are not very different from Dependency property. The problem is that C# does not provide any built in syntax for attached properties so we have use RegisterAttached to register an attached property and define the get and set access for the property.
Inherited properties are the ones whose value cascades down the visual tree and to all decendents of the target window. So when we apply a property like FontSytle it cascades down the child elements as well. To enable this we need to pass the inherit flag while constructing the metadata. We should avoid callback function along with the inherited properties because it will be called for each and every child element of the visual tree.
UIElement and ContentElement
The Visual class derives from DependencyObject and it’s the base class for the everything in the Visual Tree. We cannot derive our class from Visual though. It has functionality which might change in future version and hence is not made public. We can derive from UIElement. Practically UIELement is the base class for all visual elements in the visual tree.
Another class called the ContentElement is the base class for the text based elements like the Paragraph, span, italic, etc.
Core and Framework
Visual, UIElement and ContentElement are part of Presentation Core. Framework Element is the baseclass of User Interface elements whereas as ContentElements is the base class for text elements. As you would know WPF is splitted into core rendering services and high level framework services that provide binding, styling and so on. So Framework element is the base class of UI elements and FrameworkContentElement is the base class of text elements. You should know that DependencyObject is neither a FrameworkElement nor FrameworkContentElement type. It lives in WindowsBase dll. This contain WPF types which are not user interface elements.
Freezeable & Animatable
The Freezable class also derives from DependencyObject and the base class for brushes, pens, animations, 3D models, etc. In other words it’s the base class that defines the types that define the user interface elements rather than having the behavior themselves. One feature of Freezable elements is that they can be reused and if the value of the element is changed it will be updated at all the places. But this comes with a cost as WPF will have to remember at all the places where this element is used. But if we never want to change it then we can freeze the element. And once frozen the element will throw an exception changing and hence we have saved the cost of remembering the where all the element is used. Freezing is also useful in threading. As we know that DependencyObject supports threading but we can change the element on the thread on which it was created. But freezing helps us created an element on the worker thread and pass it on the UI thread when we are done. Freezing is really effective for large 3D complex models.
Animatable derives from Freezable. All the animation types derive from freezable except the animation object. Most of the freezable types are the things we might want to animate like a Brush’s color or a geometry’s shape. So these things are are valid targets for animation. But we also want to make animation themselves the target of animation. And 2nd order animation is not supported by WPF. So animation are one type of freezable that do not get to be a target of an animation.
Any questions. comments & feedback are most welcome.