The AvaloniaObject class is the base class for all objects that support Avalonia’s property system. It is analogous to DependencyObject in WPF and provides the infrastructure for styled properties, data binding, property inheritance, and change notification.
Overview
The AvaloniaObject provides:
- Property system with styled and direct properties
- Data binding support
- Property value inheritance
- Change notification via
INotifyPropertyChanged
- Property coercion and validation
- Animation support
- Thread affinity (dispatcher-bound)
Namespace
Inheritance
AvaloniaObject (base class for most Avalonia UI elements)
Key Concepts
Property Types
Avalonia supports two types of properties:
- Styled Properties - Properties that support styling, binding, inheritance, and animations
- Direct Properties - Lightweight properties that wrap standard CLR properties
Properties
Gets the Dispatcher that this AvaloniaObject is associated with. All property operations must occur on this dispatcher’s thread.
Gets or sets the parent object from which inherited property values are obtained. This is typically the logical or visual parent in the tree.
Methods
GetValue
public object? GetValue(AvaloniaProperty property)
public T GetValue<T>(StyledProperty<T> property)
public T GetValue<T>(DirectPropertyBase<T> property)
Gets the current value of an AvaloniaProperty.
The property to get the value for.
Returns: The current effective value of the property.
Example:
var width = control.GetValue(WidthProperty);
var background = control.GetValue(BackgroundProperty);
SetValue
public IDisposable? SetValue(
AvaloniaProperty property,
object? value,
BindingPriority priority = BindingPriority.LocalValue)
public IDisposable? SetValue<T>(
StyledProperty<T> property,
T value,
BindingPriority priority = BindingPriority.LocalValue)
public void SetValue<T>(DirectPropertyBase<T> property, T value)
Sets the value of an AvaloniaProperty.
The priority of the value. Default is LocalValue. Higher priority values take precedence.
Returns: For styled properties, an IDisposable that can be used to revert the value; null otherwise.
Example:
control.SetValue(WidthProperty, 100);
control.SetValue(BackgroundProperty, Brushes.Red);
// Setting with priority
var subscription = control.SetValue(OpacityProperty, 0.5, BindingPriority.Animation);
// Later: subscription.Dispose(); // Reverts the value
SetCurrentValue
public void SetCurrentValue(AvaloniaProperty property, object? value)
public void SetCurrentValue<T>(StyledProperty<T> property, T value)
Sets the value of a property without changing its value source. The new value will have the property’s current binding priority, and existing bindings will continue to work.
Example:
// Even if Width is bound, this sets the current value without breaking the binding
control.SetCurrentValue(WidthProperty, 200);
ClearValue
public void ClearValue(AvaloniaProperty property)
public void ClearValue<T>(AvaloniaProperty<T> property)
public void ClearValue<T>(StyledProperty<T> property)
public void ClearValue<T>(DirectPropertyBase<T> property)
Clears the local value of a property, reverting it to its default or inherited value.
Example:
control.SetValue(WidthProperty, 100);
control.ClearValue(WidthProperty); // Width reverts to default or inherited value
Bind
public IDisposable Bind(
AvaloniaProperty property,
IObservable<object?> source,
BindingPriority priority = BindingPriority.LocalValue)
public IDisposable Bind<T>(
StyledProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue)
public BindingExpressionBase Bind(AvaloniaProperty property, BindingBase binding)
Binds a property to an observable or binding expression.
The observable source that provides values.
The priority of the binding.
Returns: An IDisposable that can be used to terminate the binding.
Example:
// Bind to an observable
var subscription = control.Bind(WidthProperty, viewModel.WhenAnyValue(x => x.Width));
// Bind using a Binding object
control.Bind(TextBlock.TextProperty, new Binding("Name"));
// Later: subscription.Dispose(); // Removes the binding
GetBaseValue
public Optional<T> GetBaseValue<T>(StyledProperty<T> property)
Gets the base value of a styled property, excluding animated values.
property
StyledProperty<T>
required
The property to query.
Returns: The base value if set; otherwise, Optional<T>.Empty.
Note: This method does not return inherited or default values, only explicitly set values.
IsSet
public bool IsSet(AvaloniaProperty property)
Checks whether a property has a local value assigned or a binding targeting it.
Returns: true if the property is set; otherwise, false.
Example:
if (control.IsSet(WidthProperty))
{
// Width has been explicitly set
}
IsAnimating
public bool IsAnimating(AvaloniaProperty property)
Checks whether a property is currently being animated.
Returns: true if the property is animating; otherwise, false.
CoerceValue
public void CoerceValue(AvaloniaProperty property)
Forces coercion of the specified property value using its registered coercion callback.
CheckAccess
public bool CheckAccess()
Checks whether the current thread is the UI thread associated with this object.
Returns: true if the current thread is the UI thread; otherwise, false.
VerifyAccess
public void VerifyAccess()
Throws an exception if the current thread is not the UI thread associated with this object.
Throws: InvalidOperationException if called from the wrong thread.
Protected Methods
OnPropertyChanged
protected virtual void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
Called when an Avalonia property value changes on this object. Override this method to respond to property changes.
change
AvaloniaPropertyChangedEventArgs
required
Details about the property change, including old and new values.
Example:
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == WidthProperty)
{
// Respond to width changes
InvalidateMeasure();
}
}
SetAndRaise
protected bool SetAndRaise<T>(DirectPropertyBase<T> property, ref T field, T value)
Sets the backing field for a direct property and raises the PropertyChanged event if the value has changed.
property
DirectPropertyBase<T>
required
The property being set.
Reference to the backing field.
Returns: true if the value changed; otherwise, false.
Example:
private string? _name;
public static readonly DirectProperty<MyControl, string?> NameProperty =
AvaloniaProperty.RegisterDirect<MyControl, string?>(
nameof(Name),
o => o.Name,
(o, v) => o.Name = v);
public string? Name
{
get => _name;
set => SetAndRaise(NameProperty, ref _name, value);
}
RaisePropertyChanged
protected void RaisePropertyChanged<T>(
DirectPropertyBase<T> property,
T oldValue,
T newValue)
Manually raises the PropertyChanged event for a direct property.
property
DirectPropertyBase<T>
required
The property that changed.
Events
PropertyChanged
EventHandler<AvaloniaPropertyChangedEventArgs>?
Raised when an AvaloniaProperty value changes on this object.control.PropertyChanged += (sender, e) =>
{
if (e.Property == WidthProperty)
{
Console.WriteLine($"Width changed from {e.OldValue} to {e.NewValue}");
}
};
Indexer
public object? this[AvaloniaProperty property] { get; set; }
Gets or sets the value of a property using indexer syntax.
Example:
// Get value
var width = control[WidthProperty];
// Set value
control[WidthProperty] = 100;
Usage Examples
Basic Property Usage
public class MyControl : AvaloniaObject
{
// Define a styled property
public static readonly StyledProperty<string?> TitleProperty =
AvaloniaProperty.Register<MyControl, string?>(nameof(Title), "Default Title");
// CLR property wrapper
public string? Title
{
get => GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
}
// Usage
var control = new MyControl();
control.Title = "Hello World";
var title = control.Title;
Direct Property
public class MyControl : AvaloniaObject
{
private string? _name;
public static readonly DirectProperty<MyControl, string?> NameProperty =
AvaloniaProperty.RegisterDirect<MyControl, string?>(
nameof(Name),
o => o.Name,
(o, v) => o.Name = v);
public string? Name
{
get => _name;
set => SetAndRaise(NameProperty, ref _name, value);
}
}
Property Change Notification
public class MyControl : Control
{
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == BoundsProperty)
{
// Respond to bounds changes
Console.WriteLine($"Bounds changed to {Bounds}");
}
}
}
Data Binding
// Bind to a view model property
var binding = new Binding("UserName")
{
Source = viewModel
};
textBlock.Bind(TextBlock.TextProperty, binding);
// Bind to an observable
var subscription = textBlock.Bind(
TextBlock.TextProperty,
viewModel.WhenAnyValue(x => x.UserName)
);
Property Priorities
// Set local value (highest user priority)
control.SetValue(OpacityProperty, 0.5);
// Set animated value (overrides local value)
var animation = control.SetValue(OpacityProperty, 1.0, BindingPriority.Animation);
// Animation value is active
Console.WriteLine(control.Opacity); // 1.0
// Remove animation
animation.Dispose();
// Local value is now active
Console.WriteLine(control.Opacity); // 0.5
Thread Safety
All AvaloniaObject instances are bound to the UI thread (dispatcher) on which they were created. Property operations must occur on this thread. Use CheckAccess() to verify thread access and VerifyAccess() to enforce it.
if (!control.CheckAccess())
{
// Marshal to UI thread
control.Dispatcher.InvokeAsync(() =>
{
control.Width = 100;
});
}
else
{
control.Width = 100;
}
See Also