Avalonia.md
May 14, 2026 ยท View on GitHub
Avalonia application
This example shows how to build an Avalonia application with Pure.DI, using generated composition roots for view models and infrastructure services instead of a runtime container.
Tip
XAML binds to virtual composition roots such as App and Clock. Hint.Resolve is disabled because the sample uses explicit roots instead of generated service-locator methods.
Note
Another example with Avalonia shows how to create an application with a single composition root.
The definition of the composition is in Composition.cs. This class sets up how the object graphs will be created for the application. Do not forget to define any necessary composition roots, for example, these can be view models such as ClockViewModel:
using Pure.DI;
using static Pure.DI.Lifetime;
using static Pure.DI.RootKinds;
namespace AvaloniaApp;
partial class Composition
{
[System.Diagnostics.Conditional("DI")]
private void Setup() => DI.Setup()
.Hint(Hint.Resolve, "Off")
// Virtual roots are properties on the composition class but are not
// backed by a separate private field โ XAML reads them through the
// DataContext binding chain, so no dedicated storage is needed.
.Root<IAppViewModel>(nameof(App), kind: Virtual)
.Root<IClockViewModel>(nameof(Clock), kind: Virtual)
.Bind().As(Singleton).To<ClockViewModel>()
.Bind().To<ClockModel>()
.Bind().As(Singleton).To<Ticks>()
// Infrastructure
.Bind().To<DebugLog<TT>>()
.Bind().To<AvaloniaDispatcher>();
}
A single instance of the Composition class is defined as a static resource in App.xaml for later use within the XAML markup everywhere:
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvaloniaApp.App"
xmlns:app="using:AvaloniaApp"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant.
"Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
<Application.Resources>
<!--Creates a shared resource of type Composition and with key "Composition",
which will be further used as a data context in the views.-->
<app:Composition x:Key="Composition" />
</Application.Resources>
</Application>
This markup fragment
<Application.Resources>
<app:Composition x:Key="Composition" />
</Application.Resources>
creates a shared resource of type Composition with key "Composition", which will be further used as a data context in the views.
Dispose the composition when the Avalonia lifetime exits. This releases singleton and scoped disposable instances created by Pure.DI.
The associated application App.axaml.cs class looks like:
public class App : Application
{
public override void Initialize() => AvaloniaXamlLoader.Load(this);
public override void OnFrameworkInitializationCompleted()
{
if (Resources[nameof(Composition)] is Composition composition)
{
// Assigns the main window/view
switch (ApplicationLifetime)
{
case IClassicDesktopStyleApplicationLifetime desktop:
desktop.MainWindow = new MainWindow();
break;
case ISingleViewApplicationLifetime singleView:
singleView.MainView = new MainWindow();
break;
}
// Handles disposables
if (ApplicationLifetime is IControlledApplicationLifetime controlledLifetime)
{
controlledLifetime.Exit += (_, _) => composition.Dispose();
}
}
base.OnFrameworkInitializationCompleted();
}
}
You can now use bindings and the code-behind-free approach. All previously defined composition roots are now available from markup without any effort, e.g. Clock:
<Window 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"
xmlns:app="clr-namespace:AvaloniaApp"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaApp.MainWindow"
DataContext="{StaticResource Composition}"
x:DataType="app:Composition"
Design.DataContext="{d:DesignInstance app:DesignTimeComposition}"
Title="{Binding App.Title}"
Icon="/Assets/avalonia-logo.ico"
FontFamily="Consolas"
FontWeight="Bold">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding Clock}">
<TextBlock Text="{Binding Date}" FontSize="64" HorizontalAlignment="Center" />
<TextBlock Text="{Binding Time}" FontSize="128" HorizontalAlignment="Center" />
</StackPanel>
</Window>
To use bindings in views:
-
You can set a shared resource as a data context
DataContext="{StaticResource Composition}"and
Design.DataContext="{d:DesignInstance app:DesignTimeComposition}"for the design time -
Specify the data type in the context:
xmlns:app="clr-namespace:AvaloniaApp"x:DataType="app:Composition" -
Use the bindings as usual:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding Clock}">
<TextBlock Text="{Binding Date}" FontSize="64" HorizontalAlignment="Center" />
<TextBlock Text="{Binding Time}" FontSize="128" HorizontalAlignment="Center" />
</StackPanel>
The project file looks like this:
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup>
<PackageReference Include="Pure.DI" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
It contains an additional reference to the NuGet package:
| Pure.DI | DI source code generator |