Skip to content

9.2. Avalonia Integration

Cross-platform XAML for desktop (Win/macOS/Linux), mobile, and browser via Avalonia 12. Wires a ComponentVM<M> through an INotifyPropertyChanged adapter, similar to WPF.

9.2.1. Reactivity primitive

Avalonia bindings observe INotifyPropertyChanged.PropertyChanged and ICommand. Avalonia ships its own Dispatcher for marshalling work back to the UI thread.

9.2.2. Mapping

Avalonia VMx
INotifyPropertyChanged PropertyChangedMessage<T> on IMessageHub
ICommand RelayCommand / RelayCommand<T>
AvaloniaList<T> / ObservableCollection ServicedObservableCollection<T> or wrap ObservableList<T>
Dispatcher.UIThread.Post IDispatcher.Foreground scheduler

9.2.3. Adapter skeleton

public sealed class BindableVm<M> : INotifyPropertyChanged, IDisposable
{
    private readonly ComponentVM<M> _vm;
    private readonly IDisposable _sub;

    public BindableVm(ComponentVM<M> vm, IMessageHub hub)
    {
        _vm = vm;
        _sub = hub.Messages
            .OfType<IPropertyChangedMessage<IComponentVM>>()
            .Where(m => ReferenceEquals(m.Sender, vm))
            .ObserveOn(AvaloniaScheduler.Instance)
            .Subscribe(m => PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(m.PropertyName)));
    }

    public M Model { get => _vm.Model; set => _vm.Model = value; }
    public string Name => _vm.Name;

    public event PropertyChangedEventHandler? PropertyChanged;
    public void Dispose() => _sub.Dispose();
}

Bind in XAML: <TextBlock Text="{Binding Model.Title}"/>. For lists, wrap a ServicedObservableCollection<T> and observe its CollectionChangedMessage to refresh an AvaloniaList<T>.

9.2.4. Fuller example

examples/csharp/avalonia/NotesShowcase/ — the Notes-Showcase Avalonia flagship: end-to-end WorkspaceVM + AggregateVM6 + ConfirmationDecoratorCommand pattern (shipped in v2.2.0; ThemeVM added in v2.4.0).