iTranslated by AI
Trying out Dependency Injection in AvaloniaUI before .NET MAUI Release
[Introduction] Comparing MAUI and Avalonia
Both are frameworks for building cross-platform applications using C#.
MAUI is scheduled for release around the summer of 2022 (preview versions are already available to try).
| Comparison Item | MAUI | Avalonia |
|---|---|---|
| Developer | Microsoft | OSS |
| Supported Platforms | Android, iOS, macOS, Windows, Linux[1] | + WASM[2] |
Articles Comparing Both Frameworks
-
.Net MAUI or AvaloniaUI? - reddit
- Note: Since this is a post from a year ago, the discussion assumes Avalonia does not yet support mobile platforms.
-
Introducing .NET Multi-platform App UI (MAUI) VS Avalonia
- You can compare the activity levels, such as GitHub update frequency.
Motivation for Learning Avalonia
Personally, I lean toward choosing MAUI because it is supported by Microsoft.
However, although I haven't been reading the official Avalonia website for long, I have a feeling that XAML can be written quite concisely. Believing that the good points of Avalonia can also be applied to MAUI, I will learn Avalonia before MAUI is released.
In this article, I will try out the Dependency Injection feature.
Why DI?
AvaloniaUI is a XAML-side framework, so starting with DI is technically unusual... but since DI support is essential for resolving (hiding) dependencies effectively, I want to confirm it first.
That concludes the introduction; the next chapter begins the main topic.
Creating an Avalonia Project
Using the Visual Studio extension, I will create an MVVM template project.

[Main Topic] Dependency Injection
Avalonia has strong compatibility with ReactiveUI.
If you add using Splat, you can use DI features immediately.
However, while there is documentation on the DI functionality of ReactiveUI itself, there is no mention of how to combine it with Avalonia.
Dependency Injection - ReactiveUI
Specifically regarding registration, I tried using public virtual void RegisterServices(); which the base class of the App class possesses, but there is no guarantee that this is the standard approach.
Registration
Override the method of the App class found in App.xaml.cs.
Prepare a Person class and its interface in a separate Models folder, and register them within this method.
I will register two as named instances and the remaining one as a singleton.
// add references
using Splat;
using AvaloniaApp.Models;
public class App : Application
{
// override method
public override void RegisterServices()
{
Locator.CurrentMutable.Register<IPerson>(() => new Person("Alice"), "a");
Locator.CurrentMutable.Register<IPerson>(() => new Person("Bob"), "b");
Locator.CurrentMutable.RegisterConstant<IPerson>(new Person("Carol"));
base.RegisterServices();
}
}
Resolution
For Alice and Bob, an instance is generated every time they are called.
On the other hand, Carol's instance is generated at the time of registration.
Looking at the created at time, it can be seen that Carol was generated at an earlier time.
There is also a method called RegisterLazySingleton, but this type generates an instance when it is called.
You can infer the timing of instance generation based on whether the argument is a delegate or not.
using Splat;
public MainWindowViewModel()
{
var a = Locator.Current.GetService<IPerson>("a");
var b = Locator.Current.GetService<IPerson>("b");
var c = Locator.Current.GetService<IPerson>();
a.Greeting();
b.Greeting();
c.Greeting();
}
/*
I am Alice, created at 20:21:09
I am Bob, created at 20:21:09
I am Carol, created at 20:21:03
*/
Instance Lifetime
- Instances registered with
Registerare the same within the generated scope. - Instances registered with
Constantare the same wherever they are called.
public MainWindowViewModel()
{
var a = Locator.Current.GetService<IPerson>("a");
var c = Locator.Current.GetService<IPerson>();
a.Greeting(); // 1
c.Greeting(); // 2
GreetingTemp();
}
private void GreetingTemp()
{
Thread.Sleep(2000);
var a = Locator.Current.GetService<IPerson>("a");
var c = Locator.Current.GetService<IPerson>();
a.Greeting(); // 3
c.Greeting(); // 4
}
/*
I am Alice, created at 3:48:41
I am Carol, created at 3:48:39
I am Alice, created at 3:48:43
I am Carol, created at 3:48:39
*/
Notes on Registration
Since the instance registered later takes precedence, in the case below, there is no way to call Carol.
// Registration
Locator.CurrentMutable.RegisterConstant<IPerson>(new Person("Carol"));
Locator.CurrentMutable.RegisterConstant<IPerson>(new Person("CarolBrother"));
// Resolution
var c = Locator.Current.GetService<IPerson>(); // <- CarolBrother
Conclusion
Based on the Avalonia MVVM template, I tried out Dependency Injection.
Overriding the method inherited by App seems to provide a clean fit.
- Since it is a function without arguments, it does not strictly have to be put into
override RegisterServices.
Discussion