How To Create Advanced Custom Controls
Stuff clipped from the custom control guide.
Here's how the Border
control defines its Background
property:
The AvaloniaProperty.Register
method also accepts a number of other parameters:
defaultValue
: This gives the property a default value. Be sure to only pass value types and immutable types here as passing a reference type will cause the same object to be used on all instances on which the property is registered.inherits
: Specified that the property's default value should come from the parent control.defaultBindingMode
: The default binding mode for the property. Can be set toOneWay
,TwoWay
,OneTime
orOneWayToSource
.validate
: A validation/coercion function of typeFunc<TOwner, TValue, TValue>
. The function accepts the instance of the class on which the property is being set and the value and returns the coerced value or throws an exception for an invalid value.
A styled property is analogous to a
DependencyProperty
in other XAML frameworks.
The naming convention of the property and its backing AvaloniaProperty field is important. The name of the field is always the name of the property, with the suffix Property appended.
Using a StyledProperty
on Another Class
Sometimes the property you want to add to your control already exists on another control, Background
being a good example. To register a property defined on another control, you call StyledProperty.AddOwner
:
public static readonly StyledProperty<IBrush> BackgroundProperty =
Border.BackgroundProperty.AddOwner<Panel>();
public Brush Background
{
get { return GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
Note: Unlike WPF/UWP, a property must be registered on a class otherwise it cannot be set on an object of that class. This may change in future, however.
Readonly Properties
To create a readonly property you use the AvaloniaProperty.RegisterDirect
method. Here is how Visual
registers the readonly Bounds
property:
public static readonly DirectProperty<Visual, Rect> BoundsProperty =
AvaloniaProperty.RegisterDirect<Visual, Rect>(
nameof(Bounds),
o => o.Bounds);
private Rect _bounds;
public Rect Bounds
{
get { return _bounds; }
private set { SetAndRaise(BoundsProperty, ref _bounds, value); }
}
As can be seen, readonly properties are stored as a field on the object. When registering the property, a getter is passed which is used to access the property value through GetValue
and then SetAndRaise
is used to notify listeners to changes to the property.