diff --git a/Pure.DI.sln b/Pure.DI.sln
index d96ded25e..db32b5226 100644
--- a/Pure.DI.sln
+++ b/Pure.DI.sln
@@ -98,6 +98,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeatherForecast", "samples\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinimalWebAPI", "samples\MinimalWebAPI\MinimalWebAPI.csproj", "{60F18CFA-957B-488F-8292-467D92C17267}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SingleRootAvaloniaApp", "samples\SingleRootAvaloniaApp\SingleRootAvaloniaApp.csproj", "{7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -200,6 +202,10 @@ Global
{60F18CFA-957B-488F-8292-467D92C17267}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60F18CFA-957B-488F-8292-467D92C17267}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60F18CFA-957B-488F-8292-467D92C17267}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7C9E056B-CBA9-4548-9CDB-C5CE03C491B0} = {8163CDD7-7018-4301-A984-803C3807A6A6}
@@ -225,5 +231,6 @@ Global
{D1C043C4-ED8F-45C5-8077-EF10AA71B951} = {FA80D231-C641-4A49-99C6-0C065D818B07}
{9A3E2271-3090-4BCE-BB48-6C0724CFBE44} = {FA80D231-C641-4A49-99C6-0C065D818B07}
{60F18CFA-957B-488F-8292-467D92C17267} = {FA80D231-C641-4A49-99C6-0C065D818B07}
+ {7FCFD4F6-AFB8-479C-A103-AEBC2FC282A8} = {FA80D231-C641-4A49-99C6-0C065D818B07}
EndGlobalSection
EndGlobal
diff --git a/samples/Clock/Clock.csproj b/samples/Clock/Clock.csproj
index f546b718f..bd56f18c1 100644
--- a/samples/Clock/Clock.csproj
+++ b/samples/Clock/Clock.csproj
@@ -12,6 +12,7 @@
+
diff --git a/samples/SingleRootAvaloniaApp/App.axaml b/samples/SingleRootAvaloniaApp/App.axaml
new file mode 100644
index 000000000..f0c118e0b
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/App.axaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/App.axaml.cs b/samples/SingleRootAvaloniaApp/App.axaml.cs
new file mode 100644
index 000000000..4cdfe7e89
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/App.axaml.cs
@@ -0,0 +1,24 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+namespace AvaloniaApp;
+
+public class App : Application
+{
+ public override void Initialize() => AvaloniaXamlLoader.Load(this);
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop
+ && Resources["Composition"] is Composition composition)
+ {
+ // Assignment of the main window
+ desktop.MainWindow = composition.App.MainWindow;
+ // Handles disposables
+ desktop.Exit += (_, _) => composition.Dispose();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/AppDataContext.cs b/samples/SingleRootAvaloniaApp/AppDataContext.cs
new file mode 100644
index 000000000..6c78f3270
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/AppDataContext.cs
@@ -0,0 +1,13 @@
+namespace AvaloniaApp;
+
+using Clock.ViewModels;
+using Views;
+
+internal class AppDataContext(
+ Lazy mainWindow,
+ IClockViewModel clockViewModel)
+{
+ public MainWindow MainWindow => mainWindow.Value;
+
+ public IClockViewModel ClockViewModel => clockViewModel;
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/Assets/avalonia-logo.ico b/samples/SingleRootAvaloniaApp/Assets/avalonia-logo.ico
new file mode 100644
index 000000000..da8d49ff9
Binary files /dev/null and b/samples/SingleRootAvaloniaApp/Assets/avalonia-logo.ico differ
diff --git a/samples/SingleRootAvaloniaApp/Composition.cs b/samples/SingleRootAvaloniaApp/Composition.cs
new file mode 100644
index 000000000..8a777d627
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/Composition.cs
@@ -0,0 +1,31 @@
+// ReSharper disable UnusedMember.Local
+// ReSharper disable UnusedMember.Global
+// ReSharper disable RedundantNameQualifier
+// ReSharper disable ArrangeTypeMemberModifiers
+namespace AvaloniaApp;
+
+using Clock.Models;
+using Clock.ViewModels;
+using Pure.DI;
+using static Pure.DI.Lifetime;
+
+internal partial class Composition
+{
+ void Setup() => DI.Setup(nameof(Composition))
+ // A single compositional root for the application
+ .Root("App")
+
+ .Bind().As(Singleton).To()
+
+ // View Models
+ .Bind().To()
+
+ // Models
+ .Bind().To>()
+ .Bind().To(_ => TimeSpan.FromSeconds(1))
+ .Bind().As(Singleton).To()
+ .Bind().As(PerBlock).To()
+
+ // Infrastructure
+ .Bind().To();
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/Dispatcher.cs b/samples/SingleRootAvaloniaApp/Dispatcher.cs
new file mode 100644
index 000000000..461105620
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/Dispatcher.cs
@@ -0,0 +1,10 @@
+namespace AvaloniaApp;
+
+using Clock.ViewModels;
+
+// ReSharper disable once ClassNeverInstantiated.Global
+internal class Dispatcher: IDispatcher
+{
+ public void Dispatch(Action action) =>
+ Avalonia.Threading.Dispatcher.UIThread.Post(action);
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/Program.cs b/samples/SingleRootAvaloniaApp/Program.cs
new file mode 100644
index 000000000..cb98e4bfc
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/Program.cs
@@ -0,0 +1,21 @@
+using Avalonia;
+// ReSharper disable ClassNeverInstantiated.Global
+
+namespace AvaloniaApp;
+
+public class Program
+{
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ [STAThread]
+ public static void Main(string[] args) => BuildAvaloniaApp()
+ .StartWithClassicDesktopLifetime(args);
+
+ // Avalonia configuration, don't remove; also used by visual designer.
+ private static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .WithInterFont()
+ .LogToTrace();
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/SingleRootAvaloniaApp.csproj b/samples/SingleRootAvaloniaApp/SingleRootAvaloniaApp.csproj
new file mode 100644
index 000000000..976274dd3
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/SingleRootAvaloniaApp.csproj
@@ -0,0 +1,26 @@
+
+
+
+ $(BaseTargetFramework)
+ WinExe
+ true
+ app.manifest
+ true
+ NU1801
+ AvaloniaApp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml b/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml
new file mode 100644
index 000000000..a2dee47e0
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml.cs b/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml.cs
new file mode 100644
index 000000000..ed518af5e
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/Views/MainWindow.axaml.cs
@@ -0,0 +1,9 @@
+using Avalonia.Controls;
+
+namespace AvaloniaApp.Views;
+
+// ReSharper disable once ClassNeverInstantiated.Global
+public partial class MainWindow : Window
+{
+ public MainWindow() => InitializeComponent();
+}
\ No newline at end of file
diff --git a/samples/SingleRootAvaloniaApp/app.manifest b/samples/SingleRootAvaloniaApp/app.manifest
new file mode 100644
index 000000000..0c5b544f0
--- /dev/null
+++ b/samples/SingleRootAvaloniaApp/app.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+