Install any skill in seconds. Free to start, no credit card required.
Get Started Free →.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: navi
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 26% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 64% | 0% |
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.
ConfigureLifecycleEventsA .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).
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 |
Override CreateWindow in your App class and attach event handlers:
csharppublic 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; } }
Create a Window subclass and override the virtual methods:
csharppublic 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:
csharpprotected override Window CreateWindow(IActivationState? activationState) => new AppWindow(new AppShell());
OnStopped — use Preferences for small values or file serialization for larger state.OnResumed — read back saved values and apply to your view model.OnDestroying on Android — the back button can skip Stopped entirely.csharpprotected 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); }
| Window Event | Android Callback | |---|---| | Created | OnCreate | | Activated | OnResume | | Deactivated | OnPause | | Stopped | OnStop | | Resumed | OnRestart → OnStart → OnResume | | Destroying | OnDestroy |
| 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 | WillTerminate | .WillTerminate() |
> ⚠️ The UIKit selector names and the AddiOS builder method names differ for > activation. There is no .DidBecomeActive() or .WillResignActive() builder > method — use .OnActivated() and .OnResignActivation() or the code will not compile.
| Window Event | WinUI Callback | |---|---| | Created | OnLaunched | | Activated | Activated (foreground) | | Deactivated | Activated (background) | | Stopped | VisibilityChanged (false) | | Resumed | VisibilityChanged (true) | | Destroying | Closed |
Use ConfigureLifecycleEvents in MauiProgram.cs when you need platform-specific callbacks beyond what Window events provide:
csharpbuilder.ConfigureLifecycleEvents(events => { #if ANDROID events.AddAndroid(android => android .OnCreate((activity, bundle) => Debug.WriteLine("Android OnCreate")) .OnResume(activity => Debug.WriteLine("Android OnResume")) .OnPause(activity => Debug.WriteLine("Android OnPause")) .OnStop(activity => Debug.WriteLine("Android OnStop")) .OnDestroy(activity => Debug.WriteLine("Android OnDestroy"))); #elif IOS || MACCATALYST events.AddiOS(ios => ios .OnActivated(app => Debug.WriteLine("iOS OnActivated")) .OnResignActivation(app => Debug.WriteLine("iOS OnResignActivation")) .DidEnterBackground(app => Debug.WriteLine("iOS DidEnterBackground")) .WillEnterForeground(app => Debug.WriteLine("iOS WillEnterForeground"))); #elif WINDOWS events.AddWindows(windows => windows .OnLaunched((app, args) => Debug.WriteLine("Windows OnLaunched")) .OnActivated((window, args) => Debug.WriteLine("Windows Activated")) .OnClosed((window, args) => Debug.WriteLine("Windows Closed"))); #endif });
Created → Activated. Use OnActivated for logic that must run on every foreground entry, not OnResumed.Deactivated without Stopped. Do not perform heavy saves in OnDeactivated — the app may never actually background.Destroying directly without Stopped. Place critical save logic in both OnStopped and OnDestroying.Window instance fires its own lifecycle events. Do not assume a single global lifecycle.Preferences for quick saves, not database writes.Application.OnStart(), Application.OnSleep(), and Application.OnResume() exist for backward compatibility but bypass Window-level events. In .NET MAUI, prefer Window lifecycle events (OnActivated, OnStopped, OnResumed, etc.) for correct multi-window behavior.Other measured skills in the registry, with their headline benchmark lift.