Files
YMhut-box-C-/参考/wpfui-main/docs/documentation/navigation-view.md
T
2026-07-06 23:05:40 +08:00

324 lines
9.7 KiB
Markdown

# NavigationView
`NavigationView` is a top-level navigation control that provides a collapsible navigation pane (the "hamburger menu") and a content area. It is the primary way to implement top-level navigation in your app.
> [!TIP]
> For a complete implementation example, see the [WPF UI Gallery](https://github.com/lepoco/wpfui/tree/main/src/Wpf.Ui.Gallery) application.
## Anatomy
The `NavigationView` control has several key areas:
- **Pane**: The area on the left or top that contains navigation items.
- **Header**: An area at the top of the content area, often used for a page title or a `BreadcrumbBar`.
- **Content Area**: The main area of the control where page content is displayed.
- **AutoSuggestBox**: An optional search box integrated into the navigation pane.
- **MenuItems**: The primary list of navigation items.
- **FooterMenuItems**: A secondary list of navigation items, typically for settings or about pages.
## Basic Usage
Define `NavigationView` in your XAML and add `NavigationViewItem` objects to the `MenuItems` and `FooterMenuItems` collections.
```xml
<ui:NavigationView
xmlns:pages="clr-namespace:YourApp.Views.Pages"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
<ui:NavigationView.MenuItems>
<ui:NavigationViewItem
Content="Home"
Icon="{ui:SymbolIcon Home24}"
TargetPageType="{x:Type pages:DashboardPage}" />
<ui:NavigationViewItem
Content="Data"
Icon="{ui:SymbolIcon DataHistogram24}"
TargetPageType="{x:Type pages:DataPage}" />
</ui:NavigationView.MenuItems>
<ui:NavigationView.FooterMenuItems>
<ui:NavigationViewItem
Content="Settings"
Icon="{ui:SymbolIcon Settings24}"
TargetPageType="{x:Type pages:SettingsPage}" />
</ui:NavigationView.FooterMenuItems>
</ui:NavigationView>
```
> [!NOTE]
> `TargetPageType` is a required property on `NavigationViewItem` that specifies the page to navigate to when the item is selected. The value must be a `System.Type`.
## Programmatic Navigation
You can navigate programmatically by calling the `Navigate` method with either the `Type` of the page or its `PageTag`.
```csharp
// Navigate by Type
MyNavigationView.Navigate(typeof(SettingsPage));
// Navigate by Tag
MyNavigationView.Navigate("settings");
```
To use tags, you must define a `PageTag` on the `NavigationViewItem`. If not defined, a tag is automatically generated from the `Content` property (e.g., "Settings Page" becomes "settingspage").
```xml
<ui:NavigationViewItem
Content="Settings"
PageTag="settings"
TargetPageType="{x:Type pages:SettingsPage}" />
```
### Back Navigation
`NavigationView` automatically handles back navigation. The back button is shown when `CanGoBack` is `true`. You can also call `GoBack()` programmatically.
```csharp
if (MyNavigationView.CanGoBack)
{
MyNavigationView.GoBack();
}
```
## Pane Display Mode
Control the visibility and behavior of the navigation pane with the `PaneDisplayMode` property.
- `Left`: The pane is always open on the left.
- `Top`: The pane is shown as a horizontal bar at the top.
- `LeftCompact`: The pane is collapsed to show only icons, and expands on hover or when the hamburger button is clicked.
- `LeftMinimal`: The pane is hidden and can be opened as an overlay.
```xml
<ui:NavigationView PaneDisplayMode="Top" />
```
You can also control the pane's open state with the `IsPaneOpen` property.
> [!TIP]
> To create a responsive layout that changes `PaneDisplayMode` based on window width, bind `PaneDisplayMode` to a property in your ViewModel and update it in the `Window.SizeChanged` event.
## Header
The `Header` property provides a content area above the navigation frame. It is commonly used with a `BreadcrumbBar` to show the user's location.
```xml
<ui:NavigationView>
<ui:NavigationView.Header>
<ui:BreadcrumbBar />
</ui:NavigationView.Header>
</ui:NavigationView>
```
The `BreadcrumbBar` will automatically sync with the `NavigationView`'s navigation history.
## MVVM Integration
For MVVM applications, it is recommended to use `INavigationService` and `IPageService` for navigation and page resolution.
### 1. Service Configuration
First, register the required services and your pages/ViewModels with your dependency injection container.
```csharp
// Using Microsoft.Extensions.DependencyInjection
Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
// Main window
services.AddScoped<IWindow, MainWindow>();
services.AddScoped<MainWindowViewModel>();
// Services
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IPageService, PageService>();
// Pages and ViewModels
services.AddScoped<DashboardPage>();
services.AddScoped<DashboardViewModel>();
services.AddScoped<SettingsPage>();
services.AddScoped<SettingsViewModel>();
}).Build();
```
### 2. ViewModel Setup
In your `MainWindowViewModel`, define collections for your navigation items and bind them to the `NavigationView`.
```csharp
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private ICollection<object> _menuItems = new ObservableCollection<object>();
[ObservableProperty]
private ICollection<object> _footerMenuItems = new ObservableCollection<object>();
public MainWindowViewModel()
{
MenuItems = new ObservableCollection<object>
{
new NavigationViewItem("Home", SymbolRegular.Home24, typeof(DashboardPage)),
new NavigationViewItem("Data", SymbolRegular.DataHistogram24, typeof(DataPage))
};
FooterMenuItems = new ObservableCollection<object>
{
new NavigationViewItem("Settings", SymbolRegular.Settings24, typeof(SettingsPage))
};
}
}
```
### 3. View Setup
In your `MainWindow.xaml`, bind the `MenuItemsSource` and `FooterMenuItemsSource` properties to the collections in your ViewModel. Then, attach the `INavigationService`.
```xml
<ui:NavigationView
x:Name="RootNavigationView"
MenuItemsSource="{Binding MenuItems}"
FooterMenuItemsSource="{Binding FooterMenuItems}" />
```
```csharp
public partial class MainWindow : IWindow
{
public MainWindow(
MainWindowViewModel viewModel,
INavigationService navigationService,
IPageService pageService
)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
// Attach the service to the NavigationView
navigationService.SetNavigationControl(RootNavigationView);
// You can also set the page service, which is required for some functionalities
RootNavigationView.SetPageService(pageService);
}
public MainWindowViewModel ViewModel { get; }
}
```
### 4. Navigating from a ViewModel
Inject `INavigationService` into any ViewModel and use it to navigate.
```csharp
public partial class DashboardViewModel : ObservableObject
{
private readonly INavigationService _navigationService;
public DashboardViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
}
[RelayCommand]
private void OnGoToSettings()
{
_navigationService.Navigate(typeof(SettingsPage));
}
}
```
## Navigation Events
`NavigationView` provides several events to hook into the navigation lifecycle:
- `Navigating`: Occurs before navigation starts. Can be cancelled.
- `Navigated`: Occurs after navigation is complete.
- `SelectionChanged`: Occurs when a `NavigationViewItem` is selected.
```csharp
private void OnNavigating(NavigationView sender, NavigatingCancelEventArgs args)
{
// Don't navigate to settings if the user is not an admin
if (args.PageType == typeof(SettingsPage) && !_isAdmin)
{
args.Cancel = true;
}
}
```
## Navigation-Aware Pages
Implement `INavigationAware` on your page's code-behind or `INavigableView<T>` on your ViewModel to receive navigation events directly.
### INavigationAware
This interface is ideal for code-behind scenarios.
```csharp
public partial class MyPage : INavigationAware
{
public void OnNavigatedTo()
{
// Page was navigated to
}
public void OnNavigatedFrom()
{
// Page was navigated away from
}
}
```
### `INavigableView<T>`
This interface is designed for MVVM. Your page must inherit from `INavigableView<T>` where `T` is its ViewModel. The ViewModel will then receive the navigation calls.
**Page:**
```csharp
[GalleryPage("My Page", SymbolRegular.Page24)]
public partial class MyPage : INavigableView<MyViewModel>
{
public MyViewModel ViewModel { get; }
public MyPage(MyViewModel viewModel)
{
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
}
}
```
**ViewModel:**
```csharp
public partial class MyViewModel : ObservableObject, INavigationAware
{
public void OnNavigatedTo()
{
// Page was navigated to
}
public void OnNavigatedFrom()
{
// Page was navigated away from
}
}
```
> [!IMPORTANT]
> For `INavigableView<T>` to work, your page must have a public `ViewModel` property that returns an instance of the ViewModel.
## History and Caching
`NavigationView` maintains a navigation history.
- `History`: A collection of `Page` instances that have been visited.
- `CacheHistory`: The number of pages to keep in memory. The default is `0`. Set to a value greater than 0 to cache pages. When a cached page is navigated to, its previous state is preserved.
```xml
<ui:NavigationView CacheHistory="5" />
```
> [!CAUTION]
> Caching pages increases memory consumption. Use it only for pages that are expensive to create or where preserving state is critical. Avoid caching pages that display frequently changing data.