Prism导航
注册导航页面
注册区域
使用p:RegionManager.RegionName注册页面区域
<Window x:Class="Zhaoxi.PrismRegion.Navigation.Views.MainWindow"
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:Zhaoxi.PrismRegion.Navigation"
xmlns:p="http://prismlibrary.com/"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DockPanel>
<Grid Width="220" DockPanel.Dock="Left">
<StackPanel>
<Button Content="View A" Margin="0,3"
Command="{Binding OpenViewCommand}"
CommandParameter="ViewA"/>
<Button Content="View B" Margin="0,3"
Command="{Binding OpenViewCommand}"
CommandParameter="ViewB"/>
<Button Content="View C" Margin="0,3"/>
</StackPanel>
</Grid>
<Grid>
<!--<ContentControl p:RegionManager.RegionName="ViewRegion"/>-->
<TabControl p:RegionManager.RegionName="ViewRegion">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<!--TabItem的绑定数据源是页面对象-->
<!--TabItem的DataContext=View对象-->
<!--View对象的DataContext=对应的ViewModel-->
<Setter Property="Header" Value="{Binding DataContext.Title}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</DockPanel>
</Window>
注册界面
注册两个UserControl用于测试
<UserControl x:Class="Zhaoxi.PrismRegion.Navigation.Views.Pages.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:Zhaoxi.PrismRegion.Navigation.Views.Pages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<TextBox Text="View A" Foreground="Orange" FontSize="20"/>
<TextBlock Text="{Binding Title}" FontSize="20" Foreground="Red"/>
<Button Content="Close" Command="{Binding CloseTabCommand}"/>
</StackPanel>
</UserControl>
<UserControl x:Class="Zhaoxi.PrismRegion.Navigation.Views.Pages.ViewB"
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:Zhaoxi.PrismRegion.Navigation.Views.Pages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Text="View B" Foreground="Green" FontSize="20"/>
</Grid>
</UserControl>
RegisterTypes方法中注册界面
public class Startup : PrismBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
// 注册需要导航的子页面,只有注册了才能处理
containerRegistry.RegisterForNavigation<ViewA>();
containerRegistry.RegisterForNavigation<ViewB>();
}
}
界面关联区域
使用IRegionManager提供的RegisterViewWithRegion方法将界面名称关联到"ViewRegion"区域
public class MainWindowViewModel
{
public ICommand OpenViewCommand { get; set; }
// 区域管理,需要拿到RegionManager
IRegionManager _regionManager;
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
OpenViewCommand = new DelegateCommand<string>(DoOpenView);
}
private void DoOpenView(string viewName)
{
_regionManager.RegisterViewWithRegion("ViewRegion", viewName);
}
}
运行效果如下
导航页面传参——INavigationAware接口
页面对应的ViewAViewModel继承INavigationAware接口并实现方法
public class ViewAViewModel : INavigationAware
{
public string Title { get; set; } = "View A";
public ICommand CloseTabCommand { get; set; }
IRegionManager _regionManager;
public ViewAViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
CloseTabCommand = new DelegateCommand(DoCloseTab);
}
private void DoCloseTab()
{
}
#region INavigationAware接口方法
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 是否允许重复导航进来
// 主-》A-》B-》A (显示前对象) 返回True
// 主-》A-》B-》A(新对象) 返回false
return true;
// 编辑页面,通过主页的子项点击,打开这个页面,
// 子项有很多,可能同时打开多个子项进行编辑
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 从当前View导航出去的时候触发
// 从某个页面跳转到另一个页面的时候,可以把这个信息带过去
navigationContext.Parameters.Add("abcd", "Hello ViewA");
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
// 打开当前View的时候触发
string arg = navigationContext.Parameters.GetValue<string>("abcd");
}
#endregion
}
IsNavigationTarget
当IsNavigationTarget方法返回false时每次导航都会新建
OnNavigatedTo
在MainWindowViewModel中创建NavigationParameters对象,使用RequestNavigate在关联区域的同时传入NavigationParameters对象
public class MainWindowViewModel
{
public ICommand OpenViewCommand { get; set; }
// 区域管理,需要拿到RegionManager
IRegionManager _regionManager;
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
OpenViewCommand = new DelegateCommand<string>(DoOpenView);
}
private void DoOpenView(string viewName)
{
//_regionManager.RegisterViewWithRegion("ViewRegion", viewName);
// 打开/显示某个View的时候,希望给个参数它?
// 上面的语句无法传参
// 需要请求的View,先注册到容器中
//_regionManager.RequestNavigate("ViewRegion", viewName);
// 向某个View中传递特定参数,参数对接到View的ViewModel里
if (viewName == "ViewA")
{
NavigationParameters parameters = new NavigationParameters();
parameters.Add("abcd", "Hello");
_regionManager.RequestNavigate("ViewRegion", viewName, parameters);
}
else if (viewName == "ViewB")
_regionManager.RequestNavigate("ViewRegion", viewName);
}
}
OnNavigatedFrom
从当前View导航出去的时候触发,跳转到另一个页面的时候,可以把这个信息传递到下一个页面
第一次打开ViewB时无参数传进
打开ViewA,再次点击ViewB时参数从ViewA的OnNavigatedFrom传进ViewB的OnNavigatedTo
自动销毁——IRegionMemberLifetime接口
页面的ViewModel继承IRegionMemberLifetime接口
接口中的KeepAlive参数默认为true:非激活状态,在Region中保留
public class ViewAViewModel : INavigationAware,IRegionMemberLifetime
{
public string Title { get; set; } = "View A";
public ICommand CloseTabCommand { get; set; }
IRegionManager _regionManager;
public ViewAViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
CloseTabCommand = new DelegateCommand(DoCloseTab);
}
private void DoCloseTab()
{
}
#region IRegionMemberLifetime接口方法
// 用来控制当前页面非激活状态,是否在Region中保留
public bool KeepAlive => true;
#endregion
#region INavigationAware接口方法
#region INavigationAware接口方法
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 是否允许重复导航进来
// 主-》A-》B-》A (显示前对象) 返回True
// 主-》A-》B-》A(新对象) 返回false
return true;
// 编辑页面,通过主页的子项点击,打开这个页面,
// 子项有很多,可能同时打开多个子项进行编辑
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 从当前View导航出去的时候触发
// 从某个页面跳转到另一个页面的时候,可以把这个信息带过去
navigationContext.Parameters.Add("abcd", "Hello ViewA");
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
// 打开当前View的时候触发
string arg = navigationContext.Parameters.GetValue<string>("abcd");
}
#endregion
}
将KeepAlive参数改为false
public bool KeepAlive => false;
运行后点击ViewB,再点击ViewA
再次点击ViewB后,ViewA被自动销毁
页面离开前的事件——IConfirmNavigationRequest接口
页面ViewModel实现IConfirmNavigationRequest接口
public class ViewAViewModel : INavigationAware,IRegionMemberLifetime,IConfirmNavigationRequest
{
public string Title { get; set; } = "View A";
public ICommand CloseTabCommand { get; set; }
IRegionManager _regionManager;
public ViewAViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
CloseTabCommand = new DelegateCommand(DoCloseTab);
}
private void DoCloseTab()
{
}
#region IRegionMemberLifetime接口方法
// 用来控制当前页面非激活状态,是否在Region中保留
public bool KeepAlive => true;
#endregion
#region INavigationAware接口方法
#region INavigationAware接口方法
public bool IsNavigationTarget(NavigationContext navigationContext)
{
// 是否允许重复导航进来
// 主-》A-》B-》A (显示前对象) 返回True
// 主-》A-》B-》A(新对象) 返回false
return true;
// 编辑页面,通过主页的子项点击,打开这个页面,
// 子项有很多,可能同时打开多个子项进行编辑
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
// 从当前View导航出去的时候触发
// 从某个页面跳转到另一个页面的时候,可以把这个信息带过去
navigationContext.Parameters.Add("abcd", "Hello ViewA");
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
// 打开当前View的时候触发
string arg = navigationContext.Parameters.GetValue<string>("abcd");
}
#endregion
#region IConfirmNavigationRequest接口方法
// 当从当前页面跳转到另一个页面时触发
// OnNavigatedFrom调用前执行
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
// 打开某个页面,
if (MessageBox.Show("是否离开当前页面?", "导航提示", MessageBoxButton.YesNo) ==
MessageBoxResult.Yes)
{
/// 继续打开
///
continuationCallback?.Invoke(true);
}
else
// 不被导航
continuationCallback?.Invoke(false);
}
#endregion
}
运行后点击ViewA,再点击ViewB的时候会弹窗提醒
导航日志
编写测试程序
public class Startup : PrismBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<PrismRegion.Journal.Views.MainView>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<PrismRegion.Journal.Views.ViewA>();
containerRegistry.RegisterForNavigation<PrismRegion.Journal.Views.ViewB>();
containerRegistry.RegisterForNavigation<PrismRegion.Journal.Views.ViewC>();
}
}
public partial class App : Application
{
public App()
{
new Startup().Run();
}
}
<Window x:Class="Zhaoxi.PrismRegion.Journal.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:Zhaoxi.PrismRegion.Journal.Views"
xmlns:p="http://prismlibrary.com/"
mc:Ignorable="d"
Title="MainView" Height="450" Width="800">
<Grid>
<Button Content="Load Views" Command="{Binding BtnLoadCommand}"
VerticalAlignment="Top"/>
<ContentControl p:RegionManager.RegionName="MainRegion" Margin="0,30,0,0"/>
</Grid>
</Window>
public class MainViewModel
{
public DelegateCommand BtnLoadCommand { get; set; }
public MainViewModel(IRegionManager regionManager)
{
BtnLoadCommand = new DelegateCommand(() =>
{
regionManager.RequestNavigate("MainRegion", "ViewA");
});
}
}
<UserControl x:Class="Zhaoxi.PrismRegion.Journal.Views.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:Zhaoxi.PrismRegion.Journal.Views"
mc:Ignorable="d" FontSize="20"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<StackPanel>
<TextBlock Text="View A" Foreground="Orange" />
<Button Content="向后" Command="{Binding GoBackCommand}"/>
<Button Content="向前" Command="{Binding ForwordCommand}"/>
</StackPanel>
</Grid>
</UserControl>
页面的ViewModel继承INavigationAware接口
在OnNavigatedTo方法中取出navigationContext.NavigationService.Journal
journal.GoBack()提供导航回退
public class ViewAViewModel : INavigationAware
{
public DelegateCommand GoBackCommand { get; set; }
public DelegateCommand ForwordCommand { get; set; }
IRegionNavigationJournal journal;
public ViewAViewModel(IRegionManager regionManager)
{
GoBackCommand = new DelegateCommand(() =>
{
if (journal.CanGoBack)
{
journal.GoBack();
}
});
ForwordCommand = new DelegateCommand(() =>
{
if (journal.CanGoForward)
{
journal.GoForward();
}
else
{
regionManager.RequestNavigate("MainRegion", "ViewB");
}
});
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
journal = navigationContext.NavigationService.Journal;
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}
参照ViewA写ViewB和ViewC
修改对应ViewModel的GoBackCommand与ForwordCommand
public ViewBViewModel(IRegionManager regionManager)
{
GoBackCommand = new DelegateCommand(() =>
{
if (journal.CanGoBack)
{
journal.GoBack();
}
});
ForwordCommand = new DelegateCommand(() =>
{
if (journal.CanGoForward)
{
journal.GoForward();
}
else
{
regionManager.RequestNavigate("MainRegion", "ViewC");
}
});
}
public ViewCViewModel(IRegionManager regionManager)
{
GoBackCommand = new DelegateCommand(() =>
{
if (journal.CanGoBack)
{
journal.GoBack();
}
});
ForwordCommand = new DelegateCommand(() =>
{
if (journal.CanGoForward)
{
journal.GoForward();
}
});
}
运行后实现导航的前进后退
取消导航——IJournalAware
在ViewB的ViewModel中继承IJournalAware接口,并在实现方法中返回false。
public class ViewBViewModel : INavigationAware, IJournalAware
{
public DelegateCommand GoBackCommand { get; set; }
public DelegateCommand ForwordCommand { get; set; }
IRegionNavigationJournal journal;
public ViewBViewModel(IRegionManager regionManager)
{
GoBackCommand = new DelegateCommand(() =>
{
if (journal.CanGoBack)
{
journal.GoBack();
}
});
ForwordCommand = new DelegateCommand(() =>
{
if (journal.CanGoForward)
{
journal.GoForward();
}
else
{
regionManager.RequestNavigate("MainRegion", "ViewC");
}
});
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
journal = navigationContext.NavigationService.Journal;
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
// IJournalAware的方法实现
public bool PersistInHistory()
{
return false;
}
}
运行后,导航会取消ViewB的导航
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)