Avalonia 11 tutorial
This page contains a tutorial based on the official ToDo List tutorial from Avalonia 11's documentation but with the issues fixed. Avalonia 11 has only just been released so its not surprising that the documentation is a little rough. ;-)
This tutorial contains step-by-step instructions and screenshots using Visual Studio 2022 version 17.6.4 on Windows. It currently has no explanations and minimal steps to complete a working ToDo List app for desktop. I plan to add explanations and switch to the full cross-platform project template that supports desktop, mobile, and web later.
- Introduction to the ToDo List app
- Install the Avalonia extension
- Create a New Project
- Create a New View
- Main Window Content
- Create a Model
- Create a Fake Data Service
- Create a View Model
- Data Binding
- Add a Data Context
In this tutorial you will create a simple to do list app using Avalonia UI and the Model View View-Model (MVVM) pattern.
The final app will look like Figure B.1:
Figure B.1: Avalonia ToDo List app
- In Visual Studio 2022, navigate to Extensions | Manage Extensions.
- In the Search box, type
Avalonia
. - Select the Avalonia for Visual Studio extension and then click Download.
The original tutorial does not say the new project template names.
- In Visual Studio 2022, navigate to File | New Project.
- In the Create a new project dialog box, in the Search for templates box, enter
avalonia
. - Select Avalonia .NET MVVM App (AvaloniaUI) and then click the Next button, as shown in Figure B.2:
Figure B.2: Selecting the Avalonia .NET MVVM App (AvaloniaUI) project template
- In the Configure your new project dialog box, for the Project name enter
ToDoList
, for the Location select theC:\apps-services-net8\
folder, for the Solution name enterAppendixB
, and then click the Next button, as shown in Figure B.3:
Figure B.3: Configuring your new project name and location
The original tutorial does not specify which MVVM Toolkit to use in the latest version (although it did in the older version). You must select ReactiveUI because this tutorial uses some of its features later.
- In the Additional information dialog box, for Framework select .NET 7.0 (Standard Term Support) (you will be able to select .NET 8.0 (Long Term Support) soon after November 2023), for MVVM Toolkit select ReactiveUI, for Avalonia Version select 11.0.0, select the Use Compiled Bindings check box, clear the Remove View Locator check box, and then click the Create button, as shown in Figure B.4:
Figure B.4: Providing additional information
- Note the
MainWindow.axaml
file is open but the designer is stuck "loading", as shown in Figure B.5:
Figure B.5: Designer stuck loading
- Navigate to Build | Build ToDoList.
- After a few moments, note the designer finishes loading and shows a preview of the main window, as shown in Figure B.6:
Figure B.6: Designer showing a preview of the main window
- In Solution Explorer, right-click the
Views
folder. - Click Add | New Item.
- In the Add New Item dialog box, in C# Items, select Avalonia, and then select Avalonia UserControl (AvaloniaUI).
- For Name enter
ToDoListView
and then click the Add button. - In the
ToDoListView.axaml
file, modify the contents to replace the text that saysWelcome to Avalonia!
with a<DockPanel>
containing a button and a stack of two check boxes, as shown in the following markup:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="250" d:DesignHeight="450"
x:Class="ToDoList.Views.ToDoListView">
<DockPanel>
<Button DockPanel.Dock="Bottom"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center">
Add Item
</Button>
<StackPanel>
<CheckBox Margin="4">Walk the dog</CheckBox>
<CheckBox Margin="4">Buy some milk</CheckBox>
</StackPanel>
</DockPanel>
</UserControl>
- Save the changes to the
.axaml
file. - Build the project. Note the designer updates to show the new user interface, as shown in Figure B.7:
Figure B.7: Designer showing a preview of the user control
- In the
Views
folder, inMainWindow.axaml
, in the<Window>
element, import the namespace for working with your project's views, as shown in the following markup:xmlns:views="clr-namespace:ToDoList.Views"
. - In the
<Window>
element, change the title toAvalonia To Do List
. - Remove the <Design.DataContext> element completely.
- Replace the
<TextBlock>
with<views:ToDoListView />
.
The complete file should now look like this:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:ToDoList.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ToDoList.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
xmlns:views="clr-namespace:ToDoList.Views"
Icon="/Assets/avalonia-logo.ico"
Title="Avalonia To Do List">
<views:ToDoListView />
</Window>
- Save the changes to the file.
- Build and start the project. Note the main window now contains the user control with two check boxes, as shown in Figure B.8:
Figure B.8: Running app with user control in main window
The original tutorial changes the folder name to
DataModel
but I don't like that so I haven't. I also use the more modern file-scoped namespace declaration and I changed theString
tostring
soSystem
does not need to be imported.
- In the
Models
folder, add a new class namedToDoItem.cs
. - Modify the contents, as shown in the following code:
namespace ToDoList.Models;
public class ToDoItem
{
public string Description { get; set; } = string.Empty;
public bool IsChecked { get; set; }
}
- In the project, add a new folder named
Services
. - In the
Services
folder, add a new class file namedToDoListService.cs
. - Modify the contents, as shown in the following code:
using System.Collections.Generic; // To use IEnumerable<T>.
using ToDoList.Models; // To use ToDoItem.
namespace ToDoList.Services;
public class ToDoListService
{
public IEnumerable<ToDoItem> GetItems() => new ToDoItem[]
{
new() { Description = "Walk the dog" },
new() { Description = "Buy some milk" },
new() { Description = "Learn Avalonia", IsChecked = true },
};
}
- In the
ViewModels
folder, add a new class file namedToDoListViewModel.cs
. - Modify the contents, as shown in the following code:
using System.Collections.Generic; // To use IEnumerable<T>.
using System.Collections.ObjectModel; // To use ObservableCollection<T>.
using ToDoList.Models; // To use ToDoItem.
namespace ToDoList.ViewModels;
public class ToDoListViewModel : ViewModelBase
{
public ToDoListViewModel(IEnumerable<ToDoItem> items)
{
ListItems = new ObservableCollection<ToDoItem>(items);
}
public ObservableCollection<ToDoItem> ListItems { get; }
}
- In the
ViewModels
folder, inMainWindowViewModel.cs
, modify the statements, as shown in the following code:
using ToDoList.Services; // To use ToDoListService.
namespace ToDoList.ViewModels;
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
ToDoListService service = new();
ToDoList = new ToDoListViewModel(service.GetItems());
}
public ToDoListViewModel ToDoList { get; }
}
Warning! In the original tutorial, Steps 1 and 2 are missing, and I think because the project template selects Use Compiled Bindings by default, you would get a compile error saying:
Error AVLN:0004 Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.
. To fix this, we must import the view models namespace and then add thex:DataType
attribute to the<ItemsControl>
.
- In the
Views
folder, inToDoListView.axaml
, import the namespace for working with your view models, as shown in the following markup:
<UserControl ...
xmlns:vm="clr-namespace:ToDoList.ViewModels"
...
- In the
<DockPanel>
, replace the<StackPanel>
with an<ItemsControl>
, as shown in the following markup:
<ItemsControl ItemsSource="{Binding ListItems}" x:DataType="vm:ToDoListViewModel">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Margin="4"
IsChecked="{Binding IsChecked}"
Content="{Binding Description}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
- Save the changes to the file.
- Build the project.
- In the
Views
folder, inMainWindowView.axaml
, in<views:ToDoListView />
, add aDataContext
attribute, as shown in the following markup:
<views:ToDoListView DataContext="{Binding ToDoList}" />
- Save the changes.
- Build and run the app and note the data binding works, showing the three items from the fake service, as shown in Figure B.9:
Figure B.9: Running app with user control in main window
To be continued...