maui-accessibility
Guide for making .NET MAUI apps accessible — screen reader support via SemanticProperties, heading levels, AutomationProperties…
Guidance for dependency injection in .NET MAUI apps — service registration, lifetime selection (Singleton/Transient/Scoped), constructor injection, automatic resolution via Shell navigation, explicit resolution patterns, platform-specific registrations, and testability best
$ npx -y skills add davidortinau/maui-skills --skill maui-dependency-injection --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maui-dependency-injectionContext preview
The summary Claude sees to decide when to auto-load this skill.
Guidance for dependency injection in .NET MAUI apps — service registration, lifetime selection (Singleton/Transient/Scoped), constructor injection, automatic resolution via Shell navigation, explicit resolution patterns, platform-specific registrations, and testability best
name: maui-dependency-injection description: > Guidance for dependency injection in .NET MAUI apps — service registration, lifetime selection (Singleton/Transient/Scoped), constructor injection, automatic resolution via Shell navigation, explicit resolution patterns, platform-specific registrations, and testability best practices. USE FOR: "dependency injection", "DI registration", "AddSingleton", "AddTransient", "AddScoped", "service registration", "constructor injection", "IServiceProvider", "MauiProgram DI", "register services". DO NOT USE FOR: data binding (use maui-data-binding), Shell route setup (use maui-shell-navigation), or unit test mocking patterns (use maui-unit-testing).
| Question | Answer → Lifetime | |---|---| | Does it hold shared state or is expensive to create? | `AddSingleton` | | Is it stateless, lightweight, or per-request? | `AddTransient` | | Do you manage `IServiceScope` yourself? | `AddScoped` |
> ⚠️ **Avoid `AddScoped`** in MAUI — there is no built-in scope per page. > Using it without manually creating `IServiceScope` gives you singleton > behaviour silently, which is confusing and error-prone.
// ❌ ViewModel registered as Singleton — stale data across navigations builder.Services.AddSingleton<DetailViewModel>(); // ✅ ViewModels are Transient — fresh instance each navigation builder.Services.AddTransient<DetailViewModel>();
> Register **Pages and ViewModels as Transient**. Register **services that hold > shared state as Singleton** (e.g., `IDataService`, `HttpClient` factory).
---
XAML resources (`App.xaml` styles, converters) are parsed **during `InitializeComponent()`** — before the DI container is fully available. If a resource or converter needs a service, resolve it in `CreateWindow()`, not in the constructor.
// ❌ Resolving services during XAML parse — container may not be ready
public App(IDataService data)
{
InitializeComponent(); // XAML parses here
_data = data; // may fail for types not yet resolved
}
// ✅ Defer service resolution to CreateWindow
public partial class App : Application
{
private readonly IServiceProvider _services;
public App(IServiceProvider services)
{
_services = services;
InitializeComponent();
}
protected override Window CreateWindow(IActivationState? activationState)
{
// Safe — container is fully built
var mainPage = _services.GetRequiredService<MainPage>();
return new Window(new AppShell());
}
}---
If a Page is used in Shell XAML (`<ShellContent ContentTemplate="...">`) but **not registered** in `builder.Services`, MAUI instantiates it with the parameterless constructor. Dependencies are silently `null` — no exception.
// ❌ Page not registered — constructor injection silently skipped // builder.Services.AddTransient<DetailPage>(); // missing! // ✅ Always register pages that need injection builder.Services.AddTransient<DetailPage>(); builder.Services.AddTransient<DetailViewModel>();
---
// ❌ Service locator scattered through code — hard to test, hides dependencies
public void DoWork()
{
var service = this.Handler.MauiContext.Services.GetService<IDataService>();
service.Load();
}
// ✅ Constructor injection — explicit, testable
public class MyViewModel(IDataService dataService)
{
public void DoWork() => dataService.Load();
}> Use explicit resolution (`Handler.MauiContext.Services`) only when constructor > injection is genuinely unavailable (e.g., inside a custom handler or > platform callback).
---
When using `#if` directives for platform services, ensure the **interface** is always registered — otherwise consumers on untargeted platforms get a runtime `null`.
// ❌ No registration on Windows — GetService returns null #if ANDROID builder.Services.AddSingleton<INotificationService, AndroidNotificationService>(); #elif IOS || MACCATALYST builder.Services.AddSingleton<INotificationService, AppleNotificationService>(); #endif // ✅ Cover all platforms or provide a no-op fallback #if ANDROID builder.Services.AddSingleton<INotificationService, AndroidNotificationService>(); #elif IOS || MACCATALYST builder.Services.AddSingleton<INotificationService, AppleNotificationService>(); #elif WINDOWS builder.Services.AddSingleton<INotificationService, WindowsNotificationService>(); #endif
---
A collection of 41 skills for .NET MAUI development, UI/UX design reasoning, and Xamarin migration, designed for use with GitHub Copilot CLI and Claude Code.
Guide for making .NET MAUI apps accessible — screen reader support via SemanticProperties, heading levels, AutomationProperties…
.NET MAUI view animations, custom animations, easing functions, rotation, scale, translation, and fade effects. USE FOR: "animate…
.NET MAUI app icon configuration, splash screen setup, SVG to PNG conversion at build time, composed/adaptive icons, and…
.NET MAUI app lifecycle guidance covering the four app states (not running, running, deactivated, stopped), cross-platform Window…
Guide for .NET MAUI apps consuming .NET Aspire-hosted backend services. Covers AppHost configuration, service discovery for…
Add authentication to .NET MAUI apps. Covers WebAuthenticator for generic OAuth 2.0 / social login, and MSAL.NET for Microsoft…