/maui-app-lifecycle
.NET MAUI app lifecycle guidance — the four app states, cross-platform Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying), platform-specific lifecycle mapping, backgrounding and resume behavior, and state-preservation patterns. USE FOR: "app
$ npx -y skills add dotnet/skills --skill maui-app-lifecycle --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/maui-app-lifecycle
Context preview
The summary Claude sees to decide when to auto-load this skill.
.NET MAUI app lifecycle guidance — the four app states, cross-platform Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying), platform-specific lifecycle mapping, backgrounding and resume behavior, and state-preservation patterns. USE FOR: "app
SKILL.md
maui-app-lifecycle.SKILL.mdname: maui-app-lifecycle
description: >-
.NET MAUI app lifecycle guidance — the four app states, cross-platform Window
lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying),
platform-specific lifecycle mapping, backgrounding and resume behavior, and
state-preservation patterns.
USE FOR: "app lifecycle", "window lifecycle events", "save state on background",
"resume app", "OnStopped", "OnResumed", "backgrounding", "deactivated event",
"ConfigureLifecycleEvents", "platform lifecycle hooks".
DO NOT USE FOR: navigation events (use maui-shell-navigation),
dependency injection setup (use maui-dependency-injection),
platform API invocation (use conditional compilation and partial classes).
license: MIT
.NET MAUI App Lifecycle
Handle application state transitions correctly in .NET MAUI. This skill covers the cross-platform Window lifecycle events, their platform-native mappings, and patterns for preserving state across backgrounding and resume cycles.
When to Use
- Saving or restoring state when the app backgrounds or resumes
- Subscribing to Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying)
- Hooking into platform-native lifecycle callbacks via `ConfigureLifecycleEvents`
- Deciding where to place initialization, teardown, or refresh logic
- Understanding the difference between Deactivated and Stopped
When Not to Use
- Page-level navigation events — use Shell navigation guidance instead
- Registering services at startup — use dependency injection guidance instead
- Calling platform-specific APIs outside lifecycle context — use platform invoke guidance instead
Inputs
- The target lifecycle transition (e.g., "save draft when backgrounded", "refresh data on resume")
- Which platforms the developer targets (Android, iOS, Mac Catalyst, Windows)
- Whether the app uses multiple windows (iPad, Mac Catalyst, desktop Windows)
App States
A .NET MAUI app moves through four states:
| State | Description | |---|---| | **Not Running** | Process does not exist | | **Running** | Foreground, receiving input | | **Deactivated** | Visible but lost focus (dialog, split-screen, notification shade) | | **Stopped** | Fully backgrounded, UI not visible |
Typical flow: Not Running → Running → Deactivated → Stopped → Running (resumed) or Not Running (terminated).
Window Lifecycle Events
`Microsoft.Maui.Controls.Window` exposes six cross-platform events:
| Event | Fires when | |---|---| | `Created` | Native window allocated | | `Activated` | Window receives input focus | | `Deactivated` | Window loses focus (may still be visible) | | `Stopped` | Window is no longer visible | | `Resumed` | Window returns to foreground after Stopped | | `Destroying` | Native window is being torn down |
Subscribing via CreateWindow
Override `CreateWindow` in your `App` class and attach event handlers:
public partial class App : Application
{
protected override Window CreateWindow(IActivationState? activationState)
{
var window = base.CreateWindow(activationState);
window.Created += (s, e) => Debug.WriteLine("Created");
window.Activated += (s, e) => Debug.WriteLine("Activated");
window.Deactivated += (s, e) => Debug.WriteLine("Deactivated");
window.Stopped += (s, e) => Debug.WriteLine("Stopped");
window.Resumed += (s, e) => Debug.WriteLine("Resumed");
window.Destroying += (s, e) => Debug.WriteLine("Destroying");
return window;
}
}Subscribing via a Custom Window Subclass
Create a `Window` subclass and override the virtual methods:
public class AppWindow : Window
{
public AppWindow(Page page) : base(page) { }
protected override void OnActivated() { /* refresh UI */ }
protected override void OnStopped() { /* save state */ }
protected override void OnResumed() { /* restore state */ }
protected override void OnDestroying() { /* cleanup */ }
}Return it from `CreateWindow`:
protected override Window CreateWindow(IActivationState? activationState)
=> new AppWindow(new AppShell());Workflow: Save and Restore State on Background
1. **Identify transient state** — draft text, scroll position, form inputs, timer values. 2. **Save in `OnStopped`** — use `Preferences` for small values or file serialization for larger state. 3. **Restore in `OnResumed`** — read back saved values and apply to your view model. 4. **Also save in `OnDestroying`** on Android — the back button can skip `Stopped` entirely. 5. **Keep handlers fast** — complete within 1–2 seconds to avoid ANR on Android or watchdog kills on iOS.
protected override void OnStopped()
{
base.OnStopped();
Preferences.Set("draft_text", _viewModel.DraftText);
Preferences.Set("scroll_y", _viewModel.ScrollY);
}
protected override void OnResumed()
{
base.OnResumed();
_viewModel.DraftText = Preferences.Get("draft_text", string.Empty);
_viewModel.ScrollY = Preferences.Get("scroll_y", 0.0);
}
protected override void OnDestroying()
{
base.OnDestroying();
// Android back-button can skip Stopped
Preferences.Set("draft_text", _viewModel.DraftText);
}Platform Lifecycle Mapping
Android
| Window Event | Android Callback | |---|---| | Created | `OnCreate` | | Activated | `OnResume` | | Deactivated | `OnPause` | | Stopped | `OnStop` | | Resumed | `OnRestart` → `OnStart` → `OnResume` | | Destroying | `OnDestroy` |
iOS / Mac Catalyst
| Window Event | UIKit Callback | `AddiOS` builder method | |---|---|---| | Created | `WillFinishLaunching` / `SceneWillConnect` | `.WillFinishLaunching()` / `.SceneWillConnect()` | | Activated | `DidBecomeActive` | `.OnActivated()` | | Deactivated | `WillResignActive` | `.OnResignActivation()` | | Stopped | `DidEnterBackground` | `.DidEnterBackground()` | | Resumed | `WillEnterForeground` | `.WillEnterForeground()` | | Destroying | `WillT
Read more
name: maui-app-lifecycle description: >- .NET MAUI app lifecycle guidance — the four app states, cross-platform Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying), platform-specific lifecycle mapping, backgrounding and resume behavior, and state-preservation patterns. USE FOR: "app lifecycle", "window lifecycle events", "save state on background", "resume app", "OnStopped", "OnResumed", "backgrounding", "deactivated event", "ConfigureLifecycleEvents", "platform lifecycle hooks". DO NOT USE FOR: navigation events (use maui-shell-navigation), dependency injection setup (use maui-dependency-injection), platform API invocation (use conditional compilation and partial classes). license: MIT
.NET MAUI App Lifecycle
Handle application state transitions correctly in .NET MAUI. This skill covers the cross-platform Window lifecycle events, their platform-native mappings, and patterns for preserving state across backgrounding and resume cycles.
When to Use
- Saving or restoring state when the app backgrounds or resumes
- Subscribing to Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying)
- Hooking into platform-native lifecycle callbacks via `ConfigureLifecycleEvents`
- Deciding where to place initialization, teardown, or refresh logic
- Understanding the difference between Deactivated and Stopped
When Not to Use
- Page-level navigation events — use Shell navigation guidance instead
- Registering services at startup — use dependency injection guidance instead
- Calling platform-specific APIs outside lifecycle context — use platform invoke guidance instead
Inputs
- The target lifecycle transition (e.g., "save draft when backgrounded", "refresh data on resume")
- Which platforms the developer targets (Android, iOS, Mac Catalyst, Windows)
- Whether the app uses multiple windows (iPad, Mac Catalyst, desktop Windows)
App States
A .NET MAUI app moves through four states:
| State | Description | |---|---| | **Not Running** | Process does not exist | | **Running** | Foreground, receiving input | | **Deactivated** | Visible but lost focus (dialog, split-screen, notification shade) | | **Stopped** | Fully backgrounded, UI not visible |
Typical flow: Not Running → Running → Deactivated → Stopped → Running (resumed) or Not Running (terminated).
Window Lifecycle Events
`Microsoft.Maui.Controls.Window` exposes six cross-platform events:
| Event | Fires when | |---|---| | `Created` | Native window allocated | | `Activated` | Window receives input focus | | `Deactivated` | Window loses focus (may still be visible) | | `Stopped` | Window is no longer visible | | `Resumed` | Window returns to foreground after Stopped | | `Destroying` | Native window is being torn down |
Subscribing via CreateWindow
Override `CreateWindow` in your `App` class and attach event handlers:
public partial class App : Application
{
protected override Window CreateWindow(IActivationState? activationState)
{
var window = base.CreateWindow(activationState);
window.Created += (s, e) => Debug.WriteLine("Created");
window.Activated += (s, e) => Debug.WriteLine("Activated");
window.Deactivated += (s, e) => Debug.WriteLine("Deactivated");
window.Stopped += (s, e) => Debug.WriteLine("Stopped");
window.Resumed += (s, e) => Debug.WriteLine("Resumed");
window.Destroying += (s, e) => Debug.WriteLine("Destroying");
return window;
}
}Subscribing via a Custom Window Subclass
Create a `Window` subclass and override the virtual methods:
public class AppWindow : Window
{
public AppWindow(Page page) : base(page) { }
protected override void OnActivated() { /* refresh UI */ }
protected override void OnStopped() { /* save state */ }
protected override void OnResumed() { /* restore state */ }
protected override void OnDestroying() { /* cleanup */ }
}Return it from `CreateWindow`:
protected override Window CreateWindow(IActivationState? activationState)
=> new AppWindow(new AppShell());Workflow: Save and Restore State on Background
1. **Identify transient state** — draft text, scroll position, form inputs, timer values. 2. **Save in `OnStopped`** — use `Preferences` for small values or file serialization for larger state. 3. **Restore in `OnResumed`** — read back saved values and apply to your view model. 4. **Also save in `OnDestroying`** on Android — the back button can skip `Stopped` entirely. 5. **Keep handlers fast** — complete within 1–2 seconds to avoid ANR on Android or watchdog kills on iOS.
protected override void OnStopped()
{
base.OnStopped();
Preferences.Set("draft_text", _viewModel.DraftText);
Preferences.Set("scroll_y", _viewModel.ScrollY);
}
protected override void OnResumed()
{
base.OnResumed();
_viewModel.DraftText = Preferences.Get("draft_text", string.Empty);
_viewModel.ScrollY = Preferences.Get("scroll_y", 0.0);
}
protected override void OnDestroying()
{
base.OnDestroying();
// Android back-button can skip Stopped
Preferences.Set("draft_text", _viewModel.DraftText);
}Platform Lifecycle Mapping
Android
| Window Event | Android Callback | |---|---| | Created | `OnCreate` | | Activated | `OnResume` | | Deactivated | `OnPause` | | Stopped | `OnStop` | | Resumed | `OnRestart` → `OnStart` → `OnResume` | | Destroying | `OnDestroy` |
iOS / Mac Catalyst
| Window Event | UIKit Callback | `AddiOS` builder method | |---|---|---| | Created | `WillFinishLaunching` / `SceneWillConnect` | `.WillFinishLaunching()` / `.SceneWillConnect()` | | Activated | `DidBecomeActive` | `.OnActivated()` | | Deactivated | `WillResignActive` | `.OnResignActivation()` | | Stopped | `DidEnterBackground` | `.DidEnterBackground()` | | Resumed | `WillEnterForeground` | `.WillEnterForeground()` | | Destroying | `WillT
This repository contains the .NET team's curated set of core skills and custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io. 📊 Dashboard - Accuracy and efficiency scoring trends for contained plugins (
Repo: dotnet/skills
Other skills on dotnet-skills.
- /csharp-scripts
Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C# language/API experiments, one-file C# apps, small multi-file C# apps composed with `#:include`/`#:exclude`, or C# file-based apps linked with `#:ref`. Do
Open skill - /dotnet-pinvoke
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging
Open skill - /nuget-trusted-publishing
Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR: trusted publishing, NuGet OIDC, keyless NuGet publish, migrate from NuGet API key, NuGet/login, secure NuGet publishing. DO NOT USE FOR: publishing to
Open skill - /technology-selection
Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET, Microsoft.Extensions.AI (MEAI), Microsoft Agent Framework (MAF), GitHub Copilot SDK, ONNX Runtime, and OllamaSharp. Covers the full spectrum from classic ML through modern
Open skill - /configuring-opentelemetry-dotnet
Configure OpenTelemetry distributed tracing, metrics, and logging in ASP.NET Core using the .NET OpenTelemetry SDK. Use when adding observability, setting up OTLP exporters, creating custom metrics/spans, or troubleshooting distributed trace correlation.
Open skill - /convert-blazor-server-to-webapp
Guides conversion of a pre-.NET 8 Blazor Server app into a .NET 8+ Blazor Web App. USE FOR: migrating apps that use AddServerSideBlazor and MapBlazorHub to the AddRazorComponents/MapRazorComponents model, converting _Host.cshtml to an App.razor root component, replacing
Open skill

