In this post I’m going to explore Perspex’s version of the
PerspexProperty is the equivalent of WPF’s DependencyProperty. Dependency/Perspex properties give
you a number of important features over simple .NET properties with
- Property value inheritance. If the
FontFamilyproperty is not set on a control it will use the
FontFamilyof its parent, which if it’s not set will use the value of it’s parent and so on. In this way, setting
FontFamilyon the top-level
Windowcan affect all of the controls contained in that window.
- Attached Properties. Attached properties can be defined which can add arbitrary properties to
controls. The control itself doesn’t need to know what to do with an attached property - the
behaviour can be handled elsewhere. An example of an attached property is
- Default values. The value for each property applicable to a control doesn’t need to be stored unless it differs from the default value.
- Coercion. Perspex properties can also register a callback to handle coercion.
- Binding. The value of a
PerspexPropertycan be bound to the result of an
- Binding Priorities. Bindings may have a priority, so that values that come from the styling system can be overridden by values that are set locally.
Declaring a Perspex Property
DependencyProperty in WPF looks something like this:
A lot of boilerplate there. With generics and default parameters we can make it look a bit nicer:
What can we see here?
- PerspexProperties are typed, so no more having to cast in the getter.
- We pass the property type and owner class as a generic type to
Register()so we don’t have to write
- We used default parameter values in
Register()so that defaults don’t have to be restated.
DependencyPropertys in XAML, perspex properties need to be defined on a class that inherits
Adding a Perspex Property to Another Type
Just like in WPF, you can share perspex properties between unrelated controls by calling `PerspexProperty.AddOwner’:
Property Value Inheritance
Here we declare an inherited integer property called “Foo”:
By specifying the
inherits: true parameter in the call to
PerspexProperty.Register, we are
saying that in the absence of an explicitly set value for “Foo” on a control, the value from the
parent control should be used.
PerspexObject is defined at a lower level than the concept of “parent controls” so
PerspexObject uses the protected
InheritanceParent property to determine the parent control.
This is automatically set by
Visual (which inherits from
PerspexObject) so you shouldn’t usually
have to worry about it.
Attached properties are essentially the same as attached dependency properties in WPF. They are
defined by calling
Default values are provided in the call to
RegisterAttached. If no
default value is provided the default is taken to be
Just like in WPF, you can override the default value for a specific type:
Coercion allows a control to react to changes in a property’s value and make sure that the value is within a valid range. For example a “Percentage” property may only allow values between 0 and 100:
The coercion method must be static, so the object on which the property change has taken place is
passed as a parameter. It’s important to note that you should not assume that the type of the object
is the same as the type that registered the property as properties can be added to other classes
PerspexProperty.AddOwner. If you need to access the object on which the property change has
taken place you should check the type first.
Currently coercion cannot be overridden for other classes, this is a limitation that may need to be lifted in future.
Binding in Perspex uses Reactive Extensions’ IObservable. To bind an IObservable to a property, use the
Note that because PerspexProperty is typed, we can check that the observable is of the correct type.
To get the value of a property as an observable, call
A binding may also have a priority. The
BindingPriority enumeration gives a set of common
As you can see, lower integral values are considered to be of a higher priority. We’ll explore how priorites work in another post.
Binding in Initialization Lists
One of the goals of perspex was to make defining a UI in code almost as painless as using markup. To these ends, you can use initalization lists everywhere to give a XAML-like feel to your control declarations in C#:
This works fine for perspex properties that are exposed as standard .NET properties, but how can we make this work for attached properties and bindings? Well, C# 6 introduces a new feature called index initializers which can allow us to do this:
Nice… Now lets suppose we want to bind a property:
Yep, by putting a bang in front of the property name you can bind to a property (attached or otherwise) from the object initializer.
Binding to a property on another control? Easy:
Two way binding? Just add two bangs:
If you’re writing a control template however, you don’t want to bind at the LocalValue binding
priority, you want to bind using the
TemplatedParent binding priority. To do this use the tilde
operator instead. Here’s an example from
ScrollViewer’s control template:
As before, doubling up the tilde operator creates a two-way binding.