.NET MAUI¶
NexusLabs.Needlr.Maui integrates Needlr's source-generated dependency injection into a .NET MAUI
application. Your App, pages, and view models — plus every Needlr-discovered service across your
solution — resolve from MAUI's single built-in container, with no per-type manual registration.
Quick Start¶
Install the package in your MAUI head project:
<PackageReference Include="NexusLabs.Needlr.Maui" />
<PackageReference Include="NexusLabs.Needlr.Injection.SourceGen" />
Wire Needlr into your MauiProgram:
using NexusLabs.Needlr.Injection;
using NexusLabs.Needlr.Injection.SourceGen;
using NexusLabs.Needlr.Maui;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseNeedlr(syringe => syringe.UsingSourceGen());
return builder.Build();
}
}
That single UseNeedlr call applies every Needlr-discovered registration to builder.Services.
MAUI then builds and owns the resulting IServiceProvider, so pages and view models are constructor
-injected the same way MAUI injects any DI-registered type.
One container, populated by Needlr¶
MAUI creates exactly one DI container via MauiApp.CreateBuilder(). Rather than building a separate
Needlr provider, the MAUI integration populates MAUI's container: it calls Needlr's
IServiceCollectionPopulator against builder.Services, using builder.Configuration for
[Options]/[HttpClientOptions] binding — the same flow the ASP.NET and host integrations use.
There are two equivalent entry points:
// One-liner on the builder
builder.UseNeedlr(syringe => syringe.UsingSourceGen());
// Or the fluent form, if you already have a ConfiguredSyringe
new Syringe()
.UsingSourceGen()
.ForMaui()
.PopulateInto(builder);
Both preserve anything already registered on the builder (MAUI's own services, and your own
builder.Services.Add... calls).
Source generation on the MAUI head¶
Needlr's source generator runs on the MAUI head project like any other assembly. When
NeedlrAutoGenerate=true (the default when you reference NexusLabs.Needlr.Build), it scans the
head and registers your App, pages, views, and view models automatically.
The generator skips the per-platform application entry points — the Windows
App : MauiWinUIApplication, the Android MainApplication : MauiApplication, and the iOS/Mac
AppDelegate : MauiUIApplicationDelegate under Platforms/. These are framework-owned objects that
MAUI constructs itself and that the platform toolchains (WinRT/CsWinRT, Android) decorate with
interop members which are not accessible from generated code. They are never resolved as services,
so excluding them is both correct and necessary — without it the head would fail to compile.
Everything you actually author remains scannable:
| Type | Scanned & registered |
|---|---|
Cross-platform App : Application, AppShell : Shell |
Yes |
Pages (ContentPage), views (ContentView), custom controls |
Yes |
| View models and services | Yes |
Windows *.WinUI.App, Android MainApplication, iOS/Mac AppDelegate |
No (framework entry points) |
If you prefer to keep the head free of source generation entirely, set NeedlrAutoGenerate=false on
the head and put your injectable types in a referenced class library; UseNeedlr will still populate
MAUI's container from those generated libraries.
View models and pages¶
Because the head is scanned, your pages and view models are registered automatically. Inject a view
model into a page's constructor and assign it to BindingContext — the canonical MVVM wiring, with
no manual registration:
public partial class MainPage : ContentPage
{
public MainPage(MainPageViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
}
Needlr also registers Lazy<T> (and IReadOnlyList<T>) for every service, so you can defer creation
where MAUI needs it — for example injecting Lazy<MainPage> into App and creating the page when the
window is first shown, instead of reaching for a service locator:
public partial class App : Application
{
private readonly Lazy<MainPage> _mainPage;
public App(Lazy<MainPage> mainPage)
{
InitializeComponent();
_mainPage = mainPage;
}
protected override Window CreateWindow(IActivationState? activationState)
=> new Window(_mainPage.Value);
}
API reference¶
| Member | Description |
|---|---|
ConfiguredSyringe.ForMaui() |
Transitions a configured syringe into a MauiSyringe. |
MauiSyringe.PopulateInto(MauiAppBuilder) |
Applies the discovered registrations to the builder's service collection and returns the builder. |
MauiAppBuilder.UseNeedlr(ConfiguredSyringe) |
Populates the builder from an already-configured syringe. |
MauiAppBuilder.UseNeedlr(Func<Syringe, ConfiguredSyringe>) |
Populates the builder, choosing the discovery strategy inline (e.g. s => s.UsingSourceGen()). |
Notes¶
- The
NexusLabs.Needlr.Mauipackage targetsnet10.0and referencesMicrosoft.Maui.Controls. It builds and unit-tests without the MAUI workload — the workload is only needed to build the app head itself. - Use
UsingSourceGen()for AOT/trimming-friendly, zero-reflection discovery (recommended for mobile).UsingReflection()is also supported if you referenceNexusLabs.Needlr.Injection.Reflection.