diff --git a/docs/android/app-links.md b/docs/android/app-links.md index f2bbfd72d..eb594cb11 100644 --- a/docs/android/app-links.md +++ b/docs/android/app-links.md @@ -246,12 +246,7 @@ namespace MyNamespace; public partial class App : Application { - public App() - { - InitializeComponent(); - - MainPage = new AppShell(); - } + ... protected override async void OnAppLinkRequestReceived(Uri uri) { diff --git a/docs/data-cloud/push-notifications.md b/docs/data-cloud/push-notifications.md index 453283040..d062ff04c 100644 --- a/docs/data-cloud/push-notifications.md +++ b/docs/data-cloud/push-notifications.md @@ -956,7 +956,7 @@ To create your .NET MAUI app: IDeviceInstallationService _deviceInstallationService; IDeviceInstallationService DeviceInstallationService => - _deviceInstallationService ?? (_deviceInstallationService = Application.Current.MainPage.Handler.MauiContext.Services.GetService()); + _deviceInstallationService ?? (_deviceInstallationService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService()); public NotificationRegistrationService(string baseApiUri, string apiKey) { @@ -1214,6 +1214,8 @@ To create the app's UI: readonly IPushDemoNotificationActionService _actionService; ``` +::: moniker range="=net-maui-8.0" + 1. In the `App` constructor, resolve the `IPushDemoNotificationActionService` implementation and assign it to the `_actionService` backing field, and subscribe to the `IPushDemoNotificationActionService.ActionTriggered` event: ```csharp @@ -1228,6 +1230,24 @@ To create the app's UI: } ``` +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +1. In the `App` constructor, resolve the `IPushDemoNotificationActionService` implementation and assign it to the `_actionService` backing field, and subscribe to the `IPushDemoNotificationActionService.ActionTriggered` event: + + ```csharp + public App(IPushDemoNotificationActionService service) + { + InitializeComponent(); + + _actionService = service; + _actionService.ActionTriggered += NotificationActionTriggered; + } + ``` + +::: moniker-end + 1. In the `App` class, implement the event handler for the `IPushDemoNotificationActionService.ActionTriggered` event: ```csharp @@ -1240,7 +1260,7 @@ To create the app's UI: { MainThread.BeginInvokeOnMainThread(() => { - MainPage?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK") + Windows[0].Page?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK") .ContinueWith((task) => { if (task.IsFaulted) diff --git a/docs/fundamentals/app-lifecycle.md b/docs/fundamentals/app-lifecycle.md index 19b84fd6c..219815433 100644 --- a/docs/fundamentals/app-lifecycle.md +++ b/docs/fundamentals/app-lifecycle.md @@ -56,6 +56,8 @@ In addition to these events, the `Window` class also has the following overridab To subscribe to the `Window` lifecycle events, override the `CreateWindow` method in your `App` class to create a `Window` instance on which you can subscribe to events: +::: moniker range="=net-maui-8.0" + ```csharp namespace MyMauiApp { @@ -68,6 +70,35 @@ namespace MyMauiApp MainPage = new MainPage(); } + protected override Window CreateWindow(IActivationState? activationState) + { + Window window = new Window(new AppShell()); + + window.Created += (s, e) => + { + // Custom logic + }; + + return window; + } + } +} +``` + +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +```csharp +namespace MyMauiApp +{ + public partial class App : Application + { + public App() + { + InitializeComponent(); + } + protected override Window CreateWindow(IActivationState activationState) { Window window = base.CreateWindow(activationState); @@ -83,6 +114,8 @@ namespace MyMauiApp } ``` +::: moniker-end + Alternatively, to consume the lifecycle overrides, create a class that derives from the `Window` class ```csharp @@ -108,9 +141,13 @@ namespace MyMauiApp The `Window`-derived class can then be consumed by overriding the `CreateWindow` method in your `App` class to return a `MyWindow` instance. +::: moniker range="=net-maui-8.0" + > [!WARNING] > An `InvalidOperationException` will be thrown if the `App.MainPage` property is set and the `CreateWindow` method creates a `Window` object using the override that accepts a argument. +::: moniker-end + ## Platform lifecycle events .NET MAUI defines delegates that are invoked in response to platform lifecycle events being raised. Handlers can be specified for these delegates, using named methods or anonymous functions, which are executed when the delegate is invoked. This mechanism enables apps to be notified when common platform lifecycle events are raised. diff --git a/docs/fundamentals/dependency-injection.md b/docs/fundamentals/dependency-injection.md index a120d33d3..35a3e4bd3 100644 --- a/docs/fundamentals/dependency-injection.md +++ b/docs/fundamentals/dependency-injection.md @@ -267,6 +267,8 @@ This approach can be useful if you need to resolve a dependency from an [!WARNING] > The `Handler` property of your `Element` could be `null`, so be aware that you may need to account for this situation. For more information, see [Handler lifecycle](~/user-interface/handlers/index.md#handler-lifecycle). +::: moniker range="=net-maui-8.0" + In a view-model, the dependency injection container can be explicitly accessed through the [`Handler.MauiContext.Service`](xref:Microsoft.Maui.IMauiContext.Services) property of `Application.Current.MainPage`: ```csharp @@ -283,6 +285,28 @@ public class MainPageViewModel } ``` +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +In a view-model, the dependency injection container can be explicitly accessed through the [`Handler.MauiContext.Service`](xref:Microsoft.Maui.IMauiContext.Services) property of the `Window.Page`: + +```csharp +public class MainPageViewModel +{ + readonly ILoggingService _loggingService; + readonly ISettingsService _settingsService; + + public MainPageViewModel() + { + _loggingService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService(); + _settingsService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService(); + } +} +``` + +::: moniker-end + A drawback of this approach is that the view-model now has a dependency on the type. However, this drawback can be eliminated by passing an argument to the view-model constructor. The is resolved through automatic dependency resolution without having to register it with the dependency injection container. With this approach a type and its dependency can be automatically resolved provided that the type is registered with the dependency injection container. The can then be used for explicit dependency resolution: ```csharp @@ -303,6 +327,8 @@ In addition, an instance can be accessed on each ## Limitations with XAML resources +::: moniker range="=net-maui-8.0" + A common scenario is to register a page with the dependency injection container, and use automatic dependency resolution to inject it into the `App` constructor and set it as the value of the `MainPage` property: ```csharp @@ -313,10 +339,35 @@ public App(MyFirstAppPage page) } ``` +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +A common scenario is to register a page with the dependency injection container, and use automatic dependency resolution to inject it into the `App` constructor and set it as the first page to be displayed in the app: + +```csharp +MyFirstAppPage _firstPage; + +public App(MyFirstAppPage page) +{ + InitializeComponent(); + _firstPage = page; +} + +protected override Window CreateWindow(IActivationState? activationState) +{ + return new Window(_firstPage); +} +``` + +::: moniker-end + However, in this scenario if `MyFirstAppPage` attempts to access a `StaticResource` that's been declared in XAML in the `App` resource dictionary, a will be thrown with a message similar to `Position {row}:{column}. StaticResource not found for key {key}`. This occurs because the page resolved through constructor injection has been created before the application-level XAML resources have been initialized. A workaround for this issue is to inject an into your `App` class and then use it to resolve the page inside the `App` class: +::: moniker range="=net-maui-8.0" + ```csharp public App(IServiceProvider serviceProvider) { @@ -325,4 +376,25 @@ public App(IServiceProvider serviceProvider) } ``` +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +```csharp +MyFirstAppPage _firstPage; + +public App(IServiceProvider serviceProvider) +{ + InitializeComponent(); + _firstPage = serviceProvider.GetService(); +} + +protected override Window CreateWindow(IActivationState? activationState) +{ + return new Window(_firstPage); +} +``` + +::: moniker-end + This approach forces the XAML object tree to be created and initialized before the page is resolved. diff --git a/docs/fundamentals/shell/navigation.md b/docs/fundamentals/shell/navigation.md index 2a2a30b8d..41750a2b6 100644 --- a/docs/fundamentals/shell/navigation.md +++ b/docs/fundamentals/shell/navigation.md @@ -16,7 +16,7 @@ The class defines the following navigation- - `CurrentItem`, of type `ShellItem`, the currently selected item. - `CurrentPage`, of type , the currently presented page. - `CurrentState`, of type `ShellNavigationState`, the current navigation state of the . -- `Current`, of type , a type-casted alias for `Application.Current.MainPage`. +- `Current`, of type , which provides access to the current Shell. The , `CurrentItem`, and `CurrentState` properties are backed by objects, which means that these properties can be targets of data bindings. @@ -118,7 +118,7 @@ This example enables contextual page navigation, where navigating to the `detail ## Perform navigation -To perform navigation, a reference to the subclass must first be obtained. This reference can be obtained by casting the `App.Current.MainPage` property to a object, or through the `Shell.Current` property. Navigation can then be performed by calling the method on the object. This method navigates to a `ShellNavigationState` and returns a `Task` that will complete once the navigation animation has completed. The `ShellNavigationState` object is constructed by the method, from a `string`, or a `Uri`, and it has its `Location` property set to the `string` or `Uri` argument. +To perform navigation, a reference to the subclass must first be obtained. This reference can be obtained through the `Shell.Current` property. Navigation can then be performed by calling the method on the object. This method navigates to a `ShellNavigationState` and returns a `Task` that will complete once the navigation animation has completed. The `ShellNavigationState` object is constructed by the method, from a `string`, or a `Uri`, and it has its `Location` property set to the `string` or `Uri` argument. > [!IMPORTANT] > When a route from the Shell visual hierarchy is navigated to, a navigation stack isn't created. However, when a page that's not in the Shell visual hierarchy is navigated to, a navigation stack is created. diff --git a/docs/fundamentals/shell/search.md b/docs/fundamentals/shell/search.md index ba9d12a15..e0710bc4f 100644 --- a/docs/fundamentals/shell/search.md +++ b/docs/fundamentals/shell/search.md @@ -48,12 +48,28 @@ public class AnimalSearchHandler : SearchHandler { base.OnItemSelected(item); - // Let the animation complete - await Task.Delay(1000); + Animal animal = item as Animal; + string navigationTarget = GetNavigationTarget(); - ShellNavigationState state = (App.Current.MainPage as Shell).CurrentState; - // The following route works because route names are unique in this app. - await Shell.Current.GoToAsync($"{GetNavigationTarget()}?name={((Animal)item).Name}"); + if (navigationTarget.Equals("catdetails") || navigationTarget.Equals("dogdetails")) + { + // Navigate, passing a string + await Shell.Current.GoToAsync($"{navigationTarget}?name={((Animal)item).Name}"); + } + else + { + string lowerCasePropertyName = navigationTarget.Replace("details", string.Empty); + // Capitalise the property name + string propertyName = char.ToUpper(lowerCasePropertyName[0]) + lowerCasePropertyName.Substring(1); + + var navigationParameters = new Dictionary + { + { propertyName, animal } + }; + + // Navigate, passing an object + await Shell.Current.GoToAsync($"{navigationTarget}", navigationParameters); + } } string GetNavigationTarget() diff --git a/docs/fundamentals/single-project.md b/docs/fundamentals/single-project.md index 887b58b73..002ac6d32 100644 --- a/docs/fundamentals/single-project.md +++ b/docs/fundamentals/single-project.md @@ -221,6 +221,8 @@ public static class MauiProgram The `App` class derives from the `Application` class: +::: moniker range="=net-maui-8.0" + ```csharp namespace MyMauiApp; @@ -236,3 +238,28 @@ public class App : Application ``` In the preceding example, the `MainPage` property is set to the `AppShell` object. `AppShell` is a subclassed class that describes the visual hierarchy of the app. For more information, see [Create a .NET MAUI Shell app](shell/create.md). + +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +```csharp +namespace MyMauiApp; + +public class App : Application +{ + public App() + { + InitializeComponent(); + } + + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); + } +} +``` + +In the preceding example, a new is created whose initial content is set to the `AppShell` object. `AppShell` is a subclassed class that describes the visual hierarchy of the app. For more information, see [Create a .NET MAUI Shell app](shell/create.md). + +::: moniker-end diff --git a/docs/fundamentals/windows.md b/docs/fundamentals/windows.md index d73bafd6a..b45804618 100644 --- a/docs/fundamentals/windows.md +++ b/docs/fundamentals/windows.md @@ -53,6 +53,8 @@ The class has a `Window` property t ## Create a Window +::: moniker range="=net-maui-8.0" + By default, .NET MAUI creates a object when you set the `MainPage` property to a object in your `App` class. However, you can also override the `CreateWindow` method in your `App` class to create a object: ```csharp @@ -81,6 +83,34 @@ namespace MyMauiApp While the class has a default constructor and a constructor that accepts a argument, which represents the root page of the app, you can also call the base `CreateWindow` method to return the .NET MAUI created object. +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +By default, your .NET MAUI app overrides the `CreateWindow` method in your `App` class to create a object: + +```csharp +namespace MyMauiApp +{ + public partial class App : Application + { + public App() + { + InitializeComponent(); + } + + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); + } + } +} +``` + +::: moniker-end + +The class has a default constructor and a constructor that accepts a argument, which represents the root page of the app. + In addition, you can also create your own -derived object: ```csharp diff --git a/docs/ios/platform-specifics/navigation-bar-translucent.md b/docs/ios/platform-specifics/navigation-bar-translucent.md index 4d76539cd..75dc0d35c 100644 --- a/docs/ios/platform-specifics/navigation-bar-translucent.md +++ b/docs/ios/platform-specifics/navigation-bar-translucent.md @@ -24,16 +24,18 @@ using Microsoft.Maui.Controls.PlatformConfiguration; using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific; ... -(App.Current.MainPage as Microsoft.Maui.Controls.NavigationPage).BackgroundColor = Colors.Blue; -(App.Current.MainPage as Microsoft.maui.Controls.NavigationPage).On().EnableTranslucentNavigationBar(); +// Assume the app has a single window +(App.Current.Windows[0].Page as Microsoft.Maui.Controls.NavigationPage).BackgroundColor = Colors.Blue; +(App.Current.Windows[0].Page as Microsoft.maui.Controls.NavigationPage).On().EnableTranslucentNavigationBar(); ``` The `NavigationPage.On` method specifies that this platform-specific will only run on iOS. The `NavigationPage.EnableTranslucentNavigationBar` method, in the `Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific` namespace, is used to make the navigation bar translucent. In addition, the class in the `Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific` namespace also has a `DisableTranslucentNavigationBar` method that restores the navigation bar to its default state, and a `SetIsNavigationBarTranslucent` method which can be used to toggle the navigation bar transparency by calling the `IsNavigationBarTranslucent` method: ```csharp -(App.Current.MainPage as Microsoft.Maui.Controls.NavigationPage) +// Assume the app has a single window +(App.Current.Windows[0].Page as Microsoft.Maui.Controls.NavigationPage) .On() - .SetIsNavigationBarTranslucent(!(App.Current.MainPage as Microsoft.Maui.Controls.NavigationPage).On().IsNavigationBarTranslucent()); + .SetIsNavigationBarTranslucent(!(App.Current.Windows[0].Page as Microsoft.Maui.Controls.NavigationPage).On().IsNavigationBarTranslucent()); ``` The result is that the transparency of the navigation bar can be changed: diff --git a/docs/macios/universal-links.md b/docs/macios/universal-links.md index de34e7287..524fc14bc 100644 --- a/docs/macios/universal-links.md +++ b/docs/macios/universal-links.md @@ -204,12 +204,7 @@ namespace MyNamespace; public partial class App : Application { - public App() - { - InitializeComponent(); - - MainPage = new AppShell(); - } + ... protected override async void OnAppLinkRequestReceived(Uri uri) { diff --git a/docs/platform-integration/local-notifications.md b/docs/platform-integration/local-notifications.md index a59cf7216..e2a7840ed 100644 --- a/docs/platform-integration/local-notifications.md +++ b/docs/platform-integration/local-notifications.md @@ -478,8 +478,9 @@ For more information about dependency injection in .NET MAUI, see [Dependency in A `INotificationManagerService` implementation can be resolved through automatic dependency resolution, or through explicit dependency resolution. The following example shows using explicit dependency resolution to resolve a `INotificationManagerService` implementation: ```csharp +// Assume the app uses a single window. INotificationManagerService notificationManager = - Application.Current?.MainPage?.Handler?.MauiContext?.Services.GetService(); + Application.Current?.Windows[0].Page?.Handler?.MauiContext?.Services.GetService(); ``` For more information about resolving registered types, see [Resolution](~/fundamentals/dependency-injection.md). diff --git a/docs/platform-integration/native-embedding.md b/docs/platform-integration/native-embedding.md index 38ed2b3a8..9cf7d6e47 100644 --- a/docs/platform-integration/native-embedding.md +++ b/docs/platform-integration/native-embedding.md @@ -259,7 +259,7 @@ Before creating a native app that consumes .NET MAUI controls, you should add a 01. Delete the **Resources/raw** folder from the project. 01. Delete the **Resources/Splash** folder from the project. 01. Delete the `AppShell` class from the project. -01. Modify the `App` class so that it doesn't set the `MainPage` property: +01. Ensure the `App` class doesn't set the `MainPage` property or override the `CreateWindow` method: ```csharp public partial class App : Application @@ -330,7 +330,7 @@ Before creating a native app that consumes .NET MAUI controls, you should add a 01. Delete the **Resources/raw** folder from the project. 01. Delete the **Resources/Splash** folder from the project. 01. Delete the `AppShell` class from the project. -01. Modify the `App` class so that it doesn't set the `MainPage` property: +01. Ensure the `App` class doesn't set the `MainPage` property or override the `CreateWindow` method: ```csharp public partial class App : Application diff --git a/docs/platform-integration/snippets/shared_1/App.xaml.cs b/docs/platform-integration/snippets/shared_1/App.xaml.cs index 33ae02130..66d16170a 100644 --- a/docs/platform-integration/snippets/shared_1/App.xaml.cs +++ b/docs/platform-integration/snippets/shared_1/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } // @@ -23,8 +26,9 @@ public static void HandleAppActions(AppAction appAction) if (page != null) { - await Application.Current.MainPage.Navigation.PopToRootAsync(); - await Application.Current.MainPage.Navigation.PushAsync(page); + // Assume an app with a single window. + await Application.Current.Windows[0].Page.Navigation.PopToRootAsync(); + await Application.Current.Windows[0].Page.Navigation.PushAsync(page); } }); } diff --git a/docs/platform-integration/snippets/shared_2/App.xaml.cs b/docs/platform-integration/snippets/shared_2/App.xaml.cs index febd1f137..48825b1ac 100644 --- a/docs/platform-integration/snippets/shared_2/App.xaml.cs +++ b/docs/platform-integration/snippets/shared_2/App.xaml.cs @@ -7,11 +7,14 @@ public App() { InitializeComponent(); - MainPage = new AppShell(); - AppActions.Current.AppActionActivated += App_AppActionActivated; } + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); + } + private void App_AppActionActivated(object sender, AppActionEventArgs e) { // If the app instance this code is running in is not the current app instance, diff --git a/docs/platform-integration/snippets/shared_3/PlatformIntegration/App.xaml.cs b/docs/platform-integration/snippets/shared_3/PlatformIntegration/App.xaml.cs index e20e4da67..2f320c88f 100644 --- a/docs/platform-integration/snippets/shared_3/PlatformIntegration/App.xaml.cs +++ b/docs/platform-integration/snippets/shared_3/PlatformIntegration/App.xaml.cs @@ -2,10 +2,13 @@ public partial class App : Application { - public App() - { - InitializeComponent(); + public App() + { + InitializeComponent(); + } - MainPage = new AppShell(); - } + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); + } } diff --git a/docs/tutorials/notes-app/snippets/allnotes/App.xaml.cs b/docs/tutorials/notes-app/snippets/allnotes/App.xaml.cs index ec1f6e440..89b87d193 100644 --- a/docs/tutorials/notes-app/snippets/allnotes/App.xaml.cs +++ b/docs/tutorials/notes-app/snippets/allnotes/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); - - MainPage = new AppShell(); + } + + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-app/snippets/navigation/App.xaml.cs b/docs/tutorials/notes-app/snippets/navigation/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-app/snippets/navigation/App.xaml.cs +++ b/docs/tutorials/notes-app/snippets/navigation/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-app/snippets/note/App.xaml.cs b/docs/tutorials/notes-app/snippets/note/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-app/snippets/note/App.xaml.cs +++ b/docs/tutorials/notes-app/snippets/note/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-app/snippets/shell/App.xaml.cs b/docs/tutorials/notes-app/snippets/shell/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-app/snippets/shell/App.xaml.cs +++ b/docs/tutorials/notes-app/snippets/shell/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-mvvm/snippets/bugs/App.xaml.cs b/docs/tutorials/notes-mvvm/snippets/bugs/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-mvvm/snippets/bugs/App.xaml.cs +++ b/docs/tutorials/notes-mvvm/snippets/bugs/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-mvvm/snippets/model/App.xaml.cs b/docs/tutorials/notes-mvvm/snippets/model/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-mvvm/snippets/model/App.xaml.cs +++ b/docs/tutorials/notes-mvvm/snippets/model/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/tutorials/notes-mvvm/snippets/viewmodel-shared/App.xaml.cs b/docs/tutorials/notes-mvvm/snippets/viewmodel-shared/App.xaml.cs index ec1f6e440..feeb28b10 100644 --- a/docs/tutorials/notes-mvvm/snippets/viewmodel-shared/App.xaml.cs +++ b/docs/tutorials/notes-mvvm/snippets/viewmodel-shared/App.xaml.cs @@ -5,8 +5,11 @@ public partial class App : Application public App() { InitializeComponent(); + } - MainPage = new AppShell(); + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new AppShell()); } } } diff --git a/docs/user-interface/pages/navigationpage.md b/docs/user-interface/pages/navigationpage.md index 1ce0d2075..f06dfd9ee 100644 --- a/docs/user-interface/pages/navigationpage.md +++ b/docs/user-interface/pages/navigationpage.md @@ -62,6 +62,8 @@ Navigation methods are exposed by the `Navigation` property on any object whose constructor argument is the root page of the app, and setting the resulting object as the value of the `App.MainPage` property: ```csharp @@ -75,6 +77,29 @@ public partial class App : Application } ``` +::: moniker-end + +::: moniker range=">=net-maui-9.0" + +An app that is structured around multiple pages always has a *root* page, which is the first page added to the navigation stack. This is accomplished by creating a object whose constructor argument is the root page of the app, and setting the resulting object as the root page of a : + +```csharp +public partial class App : Application +{ + public App() + { + InitializeComponent(); + } + + protected override Window CreateWindow(IActivationState? activationState) + { + return new Window(new NavigationPage(new MainPage())); + } +} +``` + +::: moniker-end + > [!NOTE] > The `RootPage` property of a provides access to the first page in the navigation stack. diff --git a/docs/whats-new/dotnet-9.md b/docs/whats-new/dotnet-9.md index 82274d3ab..44bb2fe73 100644 --- a/docs/whats-new/dotnet-9.md +++ b/docs/whats-new/dotnet-9.md @@ -452,13 +452,13 @@ For more information, see [Xcode sync](~/macios/xcsync.md). ### Frame -The `Frame` control is marked as obsolete in .NET MAUI 9, and will be completely removed in a future release. The `Border` control should be used in its place. For more information see [Border](~/user-interface/controls/border.md). +The control is marked as obsolete in .NET MAUI 9, and will be completely removed in a future release. The control should be used in its place. For more information see [Border](~/user-interface/controls/border.md). ### MainPage -Instead of defining the first page of your app using the `MainPage` property on an `Application` object, you should set the `Page` property on a `Window` to the first page of your app. This is what happens internally in .NET MAUI when you set the `MainPage` property, so there's no behavior change introduced by the `MainPage` property being marked as obsolete. +Instead of defining the first page of your app using the property on an object, you should set the property on a to the first page of your app. This is what happens internally in .NET MAUI when you set the property, so there's no behavior change introduced by the property being marked as obsolete. -The following example shows setting the `Page` property on a `Window`, via the `CreateWindow` override: +The following example shows setting the property on a , via the `CreateWindow` override: ```csharp public partial class App : Application @@ -475,7 +475,9 @@ public partial class App : Application } ``` -The `MainPage` property is retained for .NET MAUI 9, but will be completely removed in a future release. +Code that accesses the `Application.Current.MainPage` property should now access the `Application.Current.Windows[0].Page` property for apps with a single window. For apps with multiple windows, use the `Application.Current.Windows` collection to identify the correct window and then access the `Page` property. In addition, each element features a `Window` property, that's accessible when the element is part of the current window, from which the `Page` property can be accessed (`Window.Page`). Platform code can retrieve the app's object with the `Microsoft.Maui.Platform.GetWindow` extension method. + +While the property is retained in .NET MAUI 9 it will be completely removed in a future release. ### Compatibility layouts