Avalonia: An Open Source Option for Cross-Platform UI Work
Avalonia is an open source framework for cross-platform UI work. It's commonly used for building apps in .NET that work across devices.
Jan 21st, 2025 8:33am by
Image via Unsplash+.
Getting Started
So let’s get started with Avalonia by writing something simple, while having a look at the architecture. I’ll assume you have Visual Studio Code installed, as well as .NET. I’ve covered using VS Code in various earlier posts; its flexibility makes it ideal for dipping into different projects (Avalonia itself actually recommends using JetBrains’ .NET IDE, Rider). We’ll use dotnet in the command line and that will speed up creating a simple project. Firstly, we install the Avalonia templates:
In a fresh project directory, we use the MVVM template, which also works on MacOS:
Then we’ll open up with Visual Studio Code in the folder as always:
Search for the Avalonia extensions. You will certainly want the first one:
If we select the Program.cs file and click the arrow to “Run the program associated with this file” Avalonia will immediately build a window:
That’s fine. Now let’s take a look at the basics and then do something more interesting.
If you are familiar with Windows Presentation Foundation (or WPF, which I happily assume you know nothing about) then you will have seen Extensible Application Markup Language (XAML) and Avalonia uses its own branded “axaml” file extension. You’ll also note that it appends the C# extension to mark “code behind” files. This all works, even if it is a little messy. Yes, it’s XML folks.
Thankfully, there are a few interesting files. The window is defined in “MainWindow.axaml”, and you can see the Title defined:
The only other interesting thing is the TextBlock definition.
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
...
desktop.MainWindow = new MainWindow {
DataContext = new MainWindowViewModel(),
};
...
namespace avaloniaui.ViewModels;
public partial class MainWindowViewModel : ViewModelBase {
public string Greeting { get; } = "Welcome to Avalonia!";
}
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Greeting}" FontSize="20" FontWeight="Bold" Margin="20 10"/>
<StackPanel Margin="20 25">
<TextBlock Margin="0 5" Background="LightBlue" DockPanel.Dock="Top">Choose a category</TextBlock>
<ListBox x:Name="category" SelectionChanged="CategoryChanged" Margin="1" SelectionMode="Single,AlwaysSelected">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
<StackPanel Margin="20 25">
<TextBlock Margin="0 5" Background="LightBlue" DockPanel.Dock="Top">Examples</TextBlock>
<ListBox x:Name="resultlist">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</StackPanel>
MainWindow class, we add the method:
using System;
...
public void CategoryChanged(object source, SelectionChangedEventArgs args) {
if (source is ListBox listBox) {
Console.WriteLine($"Category changed to {listBox.SelectedItem}");
}
}
Let’s try adding some data. We can actually just work in the MainWindow class. We’ll add some data and use it to fill the first ListBox and present it as the ItemSource for the category ListBox:
using System.Collections.Generic;
...
private Dictionary<string, List<string>> catgeoryDict = new Dictionary<string, List<string>>()
{
{"Trees", new List<string>(){"Larch", "Oak", "Pine", "Willow"}},
{"Birds", new List<string>(){"Eagle", "Hawk", "Owl", "Raven"}},
{"Mammals", new List<string>(){ "Bear", "Deer", "Fox", "Wolf"}},
{"Snakes", new List<string>(){"Cobra", "Python", "Rattlesnake", "Viper"}},
{"Insects", new List<string>(){"Ant", "Bee", "Fly", "Wasp"}}
};
public MainWindow()
{
InitializeComponent();
category.ItemsSource = new List<string>(catgeoryDict.Keys);
}
Now, all we need to do is to respond to the category change when a user hits a selection by filling in the right list with examples from our data. We just add one line to the event response method:
public void CategoryChanged(object source, SelectionChangedEventArgs args)
{
if (source is ListBox listBox)
{
Console.WriteLine($"Category changed to {listBox.SelectedItem}");
resultlist.ItemsSource = catgeoryDict[(string)listBox.SelectedItem].ToList();
}
}
Conclusion
That wasn’t too painful, but anything further would need us to use the ViewModel correctly. I tried using the DataGrid, a more powerful component to display data, and that was much more finicky. For brevity, there is quite a bit left unexplained, even for this simple example — this feels like quite a bit of design baggage from elsewhere. Nevertheless, it successfully serves its purpose as an open source option for cross-platform UI work.
YOUTUBE.COM/THENEWSTACK
Tech moves fast, don't miss an episode. Subscribe to our YouTube
channel to stream all our podcasts, interviews, demos, and more.