Wpf Prism 导航(参数传递,路由守卫,路由记录)
十年河东,十年河西,莫欺少年穷
学无止境,精益求精
1、新建项目wpfApp5,添加Nuget引用,并初始化App.xaml 及 cs 类
app.xaml 如下:

<Prism:PrismApplication x:Class="WpfApp5.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp5" xmlns:Prism="http://prismlibrary.com/" > <Application.Resources> </Application.Resources> </Prism:PrismApplication>
cs 类如下:

using DryIoc; using Prism.DryIoc; using Prism.Ioc; using Prism.Modularity; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; using WpfApp5.UserControls; using WpfApp5.UserControls.Models; using WpfApp5.Views; namespace WpfApp5 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : PrismApplication { protected override Window CreateShell() { //设置启动窗体为MainView return Container.Resolve<MainView>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<viewA, viewAModel>();////如果不声明名字为viewA , 默认和类名一致 containerRegistry.RegisterForNavigation<viewB, viewBModel>("viewB");////如果不声明名字为viewB , 默认和类名一致 containerRegistry.RegisterForNavigation<viewC, viewCModel>();////如果不声明名字为viewC , 默认和类名一致 } } }
说明:
xaml 中引入 Prism
xmlns:Prism="http://prismlibrary.com/"
更改标签为:
<Prism:PrismApplication> 。。。。。。 </Prism:PrismApplication>
设置启动窗体为 MainView,这里需要说明的是:窗体必须放在Views文件夹下而且必须以View结尾,ViewModel必须放在ViewModels文件夹下面,文件必须以ViewModel结尾。
App.xaml.cs 中注册了三个导航窗体(用户控件),分别为:viewA、viewB、viewC,及启动窗体MainView
2、声明 MainView
新建文件夹 Views 和 数据上下文文件夹 ViewModels,在Views文件夹中新建 MainView窗体(必须以View结尾),在ViewModels文件夹中新建 MainViewModel 上下文类(必须以Model结尾)
MainView.xaml 如下

<Window x:Class="WpfApp5.Views.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp5.Views" xmlns:Prism="http://prismlibrary.com/" Prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <Button Content="viewA" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewA"></Button> <Button Content="viewB" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewB"></Button> <Button Content="viewC" Margin="5" Height="35" Width="100" Command="{Binding BtnCommand}" CommandParameter="viewC"></Button> <Button Content="返回上一页" Margin="5" Height="35" Width="100" Command="{Binding BtnBack}"></Button> <Button Content="返回下一页" Margin="5" Height="35" Width="100" Command="{Binding BtnForward}"></Button> </StackPanel> <ContentControl Grid.Row="1" Prism:RegionManager.RegionName="ContentRegion"/> </Grid> </Window>
viewModel 类如下

public class MainViewModel : BindableBase { public DelegateCommand<string> BtnCommand { get; private set; } public DelegateCommand BtnBack { get; private set; } public DelegateCommand BtnForward { get; private set; } /// <summary> /// 区域管理器-跳转相关 /// </summary> private readonly IRegionManager regionManager; /// <summary> /// 用于保存路由跳转记录 /// </summary> private IRegionNavigationJournal journal; public MainViewModel(IRegionManager regionManager) { BtnCommand = new DelegateCommand<string>(BtnRedirect); BtnBack = new DelegateCommand(Back); BtnForward = new DelegateCommand(Forward); this.regionManager = regionManager; } /// <summary> /// 页面跳转 /// </summary> /// <param name="parma"></param> private void BtnRedirect(string parma) { NavigationParameters keys = new NavigationParameters(); keys.Add("name", "河南大学"); keys.Add("id", "58"); regionManager.Regions["ContentRegion"].RequestNavigate(parma,navigationCallback, keys); } private void navigationCallback(NavigationResult navigation) { if (navigation.Result.Value) { //如果跳转成功,则存储跳转记录 journal = navigation.Context.NavigationService.Journal; } } /// <summary> /// 返回上一页 /// </summary> private void Back() { if (journal.CanGoBack) { journal.GoBack(); } } /// <summary> /// 返回下一页 /// </summary> private void Forward() { if (journal.CanGoForward) { journal.GoForward(); } } }
说明如下:
必须继承自 BindableBase
public class MainViewModel : BindableBase
声明按钮命令事件、区域管理、路由
public DelegateCommand<string> BtnCommand { get; private set; } public DelegateCommand BtnBack { get; private set; } public DelegateCommand BtnForward { get; private set; } /// <summary> /// 区域管理器-跳转相关 /// </summary> private readonly IRegionManager regionManager; /// <summary> /// 用于保存路由跳转记录 /// </summary> private IRegionNavigationJournal journal; public MainViewModel(IRegionManager regionManager) { BtnCommand = new DelegateCommand<string>(BtnRedirect); BtnBack = new DelegateCommand(Back); BtnForward = new DelegateCommand(Forward); this.regionManager = regionManager; }
带有参数的页面跳转如下:
/// <summary> /// 页面跳转-带有参数 /// </summary> /// <param name="parma"></param> private void BtnRedirect(string parma) { NavigationParameters keys = new NavigationParameters(); keys.Add("name", "河南大学"); keys.Add("id", "58"); regionManager.Regions["ContentRegion"].RequestNavigate(parma,navigationCallback, keys); } private void navigationCallback(NavigationResult navigation) { if (navigation.Result.Value) { //如果跳转成功,则存储跳转记录 journal = navigation.Context.NavigationService.Journal; } }
navigationCallback 为回调事件,用于记录导航
返回上一页、下一页代码如下:
/// <summary> /// 返回上一页 /// </summary> private void Back() { if (journal.CanGoBack) { journal.GoBack(); } } /// <summary> /// 返回下一页 /// </summary> private void Forward() { if (journal.CanGoForward) { journal.GoForward(); } }
3、用户控件 viewA (无需遵守Prism的规则)
xaml 如下:
<UserControl x:Class="WpfApp5.UserControls.viewA" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp5.UserControls" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <StackPanel Orientation="Vertical"> <TextBlock Text="I am viewA" FontSize="24"/> <TextBlock Text="{Binding Name}" FontSize="24"/> <TextBlock Text="{Binding Id}" FontSize="24"/> </StackPanel> </Grid> </UserControl>
绑定的Name 和 Id 为参数传递的值
viewModel类如下:

public class viewAModel : BindableBase, INavigationAware, IConfirmNavigationRequest { public viewAModel() { } private string name; public string Name { get { return this.name; } set { name = value; RaisePropertyChanged(); } } private string id; public string Id { get { return this.id; } set { id = value; RaisePropertyChanged(); } } /// <summary> /// 路由保卫--可以在此方法中判断是否允许跳转--continuationCallback 会通知 OnNavigatedFrom 方法是否跳转 /// </summary> /// <param name="navigationContext"></param> public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) { var isok = false; if (MessageBox.Show("确定跳转吗", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { isok = true; } continuationCallback(isok); } /// <summary> /// 进入该viewModel时,是否创建新的viewModel对象 /// </summary> /// <param name="navigationContext"></param> /// <returns></returns> public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } /// <summary> /// 离开该viewModel执行 和 路由保卫配合使用 /// </summary> /// <param name="navigationContext"></param> public void OnNavigatedFrom(NavigationContext navigationContext) { //离开时 可能会涉及到一些数据处理,在此不做演示 } /// <summary> /// 进入该viewModel时执行 /// </summary> /// <param name="navigationContext"></param> public void OnNavigatedTo(NavigationContext navigationContext) { if (navigationContext.Parameters.ContainsKey("name")) { this.Name = navigationContext.Parameters.GetValue<string>("name"); } if (navigationContext.Parameters.ContainsKey("id")) { this.Id = navigationContext.Parameters.GetValue<string>("id"); } } }
说明如下:
继承自 BindableBase,INavigationAware, IConfirmNavigationRequest
public class viewAModel : BindableBase, INavigationAware, IConfirmNavigationRequest
BindableBase(用于双向绑定),INavigationAware(用于导航跳转), IConfirmNavigationRequest(用于导航跳转前,确认是否跳转,即路由保卫)
1、进入用户控件viewModel时执行
/// <summary> /// 进入该viewModel时执行 /// </summary> /// <param name="navigationContext"></param> public void OnNavigatedTo(NavigationContext navigationContext) { if (navigationContext.Parameters.ContainsKey("name")) { this.Name = navigationContext.Parameters.GetValue<string>("name"); } if (navigationContext.Parameters.ContainsKey("id")) { this.Id = navigationContext.Parameters.GetValue<string>("id"); } }
这里我们判断URL是否含有相关参数,有的话,则接收,赋值
2、进入该viewModel时,是否重新创建该viewmodle对象
/// <summary> /// 进入该viewModel时,是否创建新的viewModel对象 /// </summary> /// <param name="navigationContext"></param> /// <returns></returns> public bool IsNavigationTarget(NavigationContext navigationContext) { return true; }
3、离开viewMdoel时
/// <summary> /// 离开该viewModel执行 和 路由保卫配合使用 /// </summary> /// <param name="navigationContext"></param> public void OnNavigatedFrom(NavigationContext navigationContext) { //离开时 可能会涉及到一些数据处理,在此不做演示 } /// <summary> /// 路由保卫--可以在此方法中判断是否允许跳转--continuationCallback 会通知 OnNavigatedFrom 方法是否跳转 /// </summary> /// <param name="navigationContext"></param> public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback) { var isok = false; if (MessageBox.Show("确定跳转吗", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { isok = true; } continuationCallback(isok); }
ConfirmNavigationRequest 可以理解为路由保卫,用于判断是否可以跳转, continuationCallback 为回调函数,当它的参数为true时,则允许跳转,否则不跳转。
4、双向绑定
private string name; public string Name { get { return this.name; } set { name = value; RaisePropertyChanged(); } } private string id; public string Id { get { return this.id; } set { id = value; RaisePropertyChanged(); } }
注意使用 RaisePropertyChanged();方法即可
@天才卧龙的博客
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
2020-12-01 VUE 生命周期