Skip to content

9. Avalonia

Avalonia is a UI framework to develop cross-platform applications for Windows, macOS, Linux, iOS, Android, and web browsers using .NET.

Bugs

While I developed some demo applications, I realized, some things are buggy, i.e. some packages do not play together nicely. Once, the vertical scrollbar was only visible, if the ListBox was in a DockPanel. Do not invest too much time and do not question yourself too long, it might be a bug and not your fault.na

9.1 Architecture

Below you find a high level overview of the architecture of Avalonia. Basically, the cross platform capability is possible by drawing the UI on a canvas (IRenderingPlatform).

Architecture
High level architecture overview

9.2 Getting Started

We will use Rider, which has Avalonia pre-installed. In addition, install the extension AvaloniaRider to get live preview for Avalonia XAML files.

9.3 UI

UI composition UI repeating
UI Composition

Avalonia is a complete UI framework and hence it provides many built-in controls to compose your UI. In addition, there are many third party libraries. And you may define your own controls, custom controls.

Most likely you will structure your screens with the following basic elements

Example

Create your first app in Avalonia following the instructions of Test Drive, but using the template Avalonia .NET App provided by Rider. This template will not add the text-block with the greeting as shown in the instructions, but you may simply add

<TextBlock Text="hello" HorizontalAlignment="Center" VerticalAlignment="Center"/>

The figure below shows an example for margin, border, StackPanel and the corresponding XAML code, more see Alignment, Margins and Padding.

margin etc.
Margin etc.
<Border Background="LightBlue"
        BorderBrush="Black"
        BorderThickness="2"
        Padding="15">
<StackPanel Background="White"
            HorizontalAlignment="Center"
            VerticalAlignment="Top">
    <TextBlock Margin="5,0"
                FontSize="18"
                HorizontalAlignment="Center">
    Alignment, Margin and Padding Sample
    </TextBlock>
    <Button HorizontalAlignment="Left" Margin="20">Button 1</Button>
    <Button HorizontalAlignment="Right" Margin="10">Button 2</Button>
    <Button HorizontalAlignment="Stretch">Button 3</Button>
</StackPanel>
</Border>

Tip

To get used to XAML and the grid layout watch 📹 Avalonia UI - Grid Basics.

Tip

Use the playground to explore the built-in controls.

9.4 MVVM

There are two tutorials provided.

Example

Follow the instructions to create a todo app and a music store app Samples & Tutorials. Make sure, you understand the concepts and do each step to practice your programming skills. For the todo-App start your terminal in Rider (bottom left) and create the ViewModels etc. using the CLI. The music store app gives instructions for Rider. The instructions are detailed, but not for dummies, i.e. you need to understand what you are doing to get a running app.

Data Binding
Avalonia UI and MVVM

The documentation recommends to use ReactiveUI to implement MVVM in Avalonia. It is automatically added if you create a new Avalonia MVVM project. However, there is another widely used MVVM library, which we will use with MAUI. I therefore suggest, you use CommunityToolkit.Mvvm and whatch the video to switch from ReactiveUI to MVVM Toolkit 📹 Learn Avalonia UI - Replace ReactiveUI with CommunityToolkit.Mvvm.

In the following you will find some snippets to implement MVVM in Avalonia with the toolkit.

using System;
using System.ComponentModel.DataAnnotations;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MVVM.Models;

namespace MVVM.ViewModels;

public partial class AddStudentViewModel : ObservableValidator
{
    [ObservableProperty] 
    private DateTimeOffset _birthday = DateTimeOffset.Now;

    [Required] [MinLength(2)] [MaxLength(100)] 
    [NotifyCanExecuteChangedFor(nameof(SaveCommand))] 
    [ObservableProperty]
    private string _name = "";

    [RelayCommand(CanExecute = nameof(CanSave))]
    private void Save()
    {
        StudentModel.GetStudentModel().Add(new StudentModel.Student(Name, Birthday.DateTime));
        Name = "";
    }

    private bool CanSave()
    {
        return !string.IsNullOrWhiteSpace(Name);
    }
}
The ViewModel will derive from ObservableValidator if you need validation and from ObservableObject otherwise. With the attributes shown in the code above, you may define observable properties and commands. The toolkit generates the corresponding bindable public properties automatically. That's the reason for the partial in the class definition.

Here is the control binding to this viewmodel.

<UserControl ...
    xmlns:viewModels="clr-namespace:MVVM.ViewModels"
    x:Class="MVVM.Views.AddStudentView" 
    x:DataType="viewModels:AddStudentViewModel">
    <StackPanel Orientation="Vertical" Spacing="10">
        <Label>Name</Label>
        <TextBox Text="{Binding Name}" />
        <DatePicker Name="DatePicker" Margin="10" SelectedDate="{Binding Birthday}" />
        <Button Command="{Binding SaveCommand}">Add</Button>
    </StackPanel>
</UserControl>

ReactUI & MVVM Toolkit

Many users seem to use both packages side by side. Hence, if the documentation states examples using ReactUI and it is too difficult to adapt it for MVVM Toolkit, use it as it is.

9.5 Form Validation

Avalonia provides different ways to communicate failed validation of input fields to the user, see the Validating a Property. ObservableValidator describes how to do validation with the recommended MVVM Toolkit. See the example above.

9.6 UI Thread

As discussed in Asynchronous Programming you need to program asynchronously whenever you have tasks lasting longer than 50 ms. The article How To Access the UI Thread gives you the details for Avalonia.

9.7 Logging

You can simply use Log. to log information, see Logging. In addition, there are more sophisticated libraries like Serilog and NLog.

9.8 Localization