Skip to content

Repository files navigation

Extensions.WinUI.Hosting

Cloris.Extensions.WinUI.Hosting provides a dependency-injection-based startup pipeline for WinUI 3 applications.

Its primary capabilities are:

  • Constructor injection for pages opened through the standard Frame.Navigate(typeof(Page)) API.
  • NativeAOT-compatible application hosting and generated XAML metadata registration.

The package includes a source generator that registers the XamlMetaDataProvider produced by the WinUI XAML compiler. XamlMetadataApplication and a manually implemented IXamlMetadataProvider can bridge that metadata provider to the application service provider so registered framework elements can be activated through dependency injection.

Install

dotnet add package Cloris.Extensions.WinUI.Hosting

Application

Define the application in C# and derive it from XamlMetadataApplication. The concrete application remains partial because CsWinRT requires concrete WinRT types to be partial for trimming and NativeAOT support.

using Cloris.Extensions.WinUI.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

var builder = WinUIApplicationBuilder.Create<MyApplication>();

builder.Services
    .AddSingleton<MainWindow>()
    .AddTransient<SettingsViewModel>()
    .AddTransient<AccountSummaryViewModel>();

builder
    .AddView<SettingsPage>()
    .AddView<AccountSummaryView>();

builder.Build().Run();

public sealed partial class MyApplication(IServiceProvider services) : XamlMetadataApplication
{
    public MainWindow MainWindow { get => field ??= services.GetRequiredService<MainWindow>(); }

    protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        Resources.MergedDictionaries.Add(new XamlControlsResources());
        Resources.MergedDictionaries.Add(new ApplicationResources());
        MainWindow.Activate();
    }
}

The builder registers MyApplication as a singleton and resolves it inside the WinUI application callback. Create<MyApplication>() uses public constructors through Microsoft dependency injection. The first host that runs establishes the process-wide XAML metadata and dependency-injection root. Resources, windows, and application lifecycle behavior remain owned by the concrete application.

After Build() and before Run(), WinUIApplicationHost<TApplication>.Services exposes the root IServiceProvider for non-UI startup work. The host owns and disposes that provider when the application ends.

var host = builder.Build();
host.Services.GetRequiredService<ApplicationStartup>().Initialize();
host.Run();

Custom application

Instead of deriving from XamlMetadataApplication, an application defined entirely in C# can derive from Application and implement IXamlMetadataProvider directly. Forwarding to XamlMetadataProviderRegistry.Create() preserves XAML activation through the application service provider and the Inject markup extension.

using Cloris.Extensions.WinUI.Hosting;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;

public sealed partial class MyApplication : Application, IXamlMetadataProvider
{
    public IXamlType? GetXamlType(Type type) => XamlMetadataProviderRegistry.Create().GetXamlType(type);

    public IXamlType? GetXamlType(string fullName) => XamlMetadataProviderRegistry.Create().GetXamlType(fullName);

    public XmlnsDefinition[] GetXmlnsDefinitions() => XamlMetadataProviderRegistry.Create().GetXmlnsDefinitions();
}

The generator only registers the XAML compiler's metadata provider. It does not generate an App.xaml bridge or entry point; App.xaml applications remain outside this hosting contract.

View activation

Register the page, then use the standard WinUI navigation API. No custom Frame or navigation abstraction is required:

builder.AddView<SettingsPage>();

frame.Navigate(typeof(SettingsPage));

SettingsPage is resolved from the application service provider, so its public constructor can receive view models and other registered services without requiring a parameterless constructor.

Call AddView<TView>() for each FrameworkElement that XAML must create through dependency injection, including pages passed to Frame.Navigate(Type) and custom controls placed in a content host. It adds a transient DI registration and records the exact XAML type for metadata interception.

Register view models and other dependencies on builder.Services with the lifetime that fits the application. Unregistered XAML types keep the normal WinUI activation path.

Root windows are owned by the concrete application lifecycle rather than XAML type activation. Register them normally and resolve them from OnLaunched as shown above.

When a custom control is declared directly in compiled XAML, the WinUI XAML compiler still requires its public parameterless constructor. Use the Inject markup extension when only its data context needs service resolution:

[Microsoft.UI.Xaml.Data.Bindable]
public sealed class AccountSummaryViewModel
{
    public string Title { get; } = "Account summary";
}
<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:hosting="using:Cloris.Extensions.WinUI.Hosting"
    xmlns:vm="using:MyApplication.ViewModels"
    x:DataType="vm:AccountSummaryViewModel"
    DataContext="{hosting:Inject ServiceType=vm:AccountSummaryViewModel}">

    <TextBlock Text="{Binding Title, Mode=OneTime}" />
</UserControl>

Inject performs required-service resolution and honors the registered lifetime. For constructor injection into a control itself, register that control through AddView<TView>() and place it in a content host.

The generator is included in the NuGet package. Applications that reference the projects directly must also reference Extensions.WinUI.Hosting.Generator as an analyzer because analyzer references are not transitive across normal project references.

Sample

samples/HostingSample is an unpackaged WinUI 3 application that uses the direct Application + IXamlMetadataProvider mode, resolves a startup service from the built host, and exercises explicit AddView activation for pages opened through Frame.Navigate(Type) and a custom control whose data context uses Inject.

dotnet run --project samples/HostingSample/HostingSample.csproj -c Debug -p:Platform=x64

The sample can also be published as a self-contained NativeAOT application:

dotnet publish samples/HostingSample/HostingSample.csproj -c Release -p:Platform=x64 -r win-x64 --self-contained true -p:PublishAot=true -p:WindowsAppSDKSelfContained=true

About

Reusable WinUI 3 application hosting with dependency injection and generated XAML metadata registration.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages