1.搭建
(1)通过NuGet安装程序包Prism.DryIoc
。
(2)在App.xaml中引用Prism命名空间,项目应用对象改为PrismApplication
,并且删除StartupUri
。
<prism:PrismApplication x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:prism="http://prismlibrary.com/">
</prism:PrismApplication>
(3)App.xaml.cs 实现接口由Application-->PrismApplication,并实现接口方法。
public partial class App : PrismApplication
{
// 关系:PrismApplication 继承于 PrismApplicationBase 继承于 Application
// CreateShell()主要负责启动一个主页面。
protected override Window CreateShell()
{
return Container.Resolve<Main>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
(4)动态绑定上下文
满足以下三条,不需要XXX.xaml.cs中手动绑定DataContext,实现自动绑定ViewModel。
- 窗体|页面|用户控件必须放到Views文件夹下
- 模型必须放到ViewModels文件夹下
- 模型l的名称,必须是窗体名称开头,且以ViewModel结尾
- 自动绑定设置
prism:ViewModelLocator.AutoWireViewModel="True"
(可省略)
2.区域
(1)添加ContentControl
用来存放区域
<Window x:Class="WpfApp1.Views.Main"
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:WpfApp1"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<!--命令绑定,传入参数CommandParameter-->
<Button Command="{Binding OpenCommand}" CommandParameter="PageA" Content="打开模块A" Margin="5"/>
</StackPanel>
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"></ContentControl>
</Grid>
</Window>
(2)新建用户控件
<UserControl x:Class="WpfApp1.Views.PageA"
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:WpfApp1.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Text="我是PageA" FontSize="70"/>
</Grid>
</UserControl>
在App.xaml.cs中注册用户控件
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<PageA>();
}
(3)在ViewModel中通过区域找到用户控件
namespace WpfApp1.ViewModels
{
public class MainViewModel:BindableBase
{
private readonly IRegionManager regionManager;
public DelegateCommand<string> OpenCommand { get; private set; }
//把接口 IRegionManager 注入
public MainViewModel(IRegionManager regionManager)
{
OpenCommand = new DelegateCommand<string>(Open);
this.regionManager = regionManager;
}
void Open(string name)
{
//通过regionManager接口获取当前全局定义的可用区域
//通过依赖注入的方式动态的往这个区域注入内容
this.regionManager.Regions["ContentRegion"].RequestNavigate(name);
}
}
}
4.模块化
模块化功能和区域相似,但模块化范围更广,它是将项目当作模块来充当跳转页面(因此项目中的view需要是用户控件)。而区域只是把用户控件当作跳转界面。
(1)新建模块类库项目
(2)添加用户控件PageA
(3)添加XXXProfile类,并实现IMoudle
接口
注意:区域注册是在App.xaml.cs中,而模块是在此文件中注册
class ModuleProfile : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
//<视图,视图模型>上下文绑定
containerRegistry.RegisterForNavigation<PageA,PageAViewModel>();
}
}
(4)在主程序App.xaml.cs中管理注册的模块
方式一:引用模块dll,重写ConfigureModuleCatalog
方法
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
//ConfigureModuleCatalog()主要负责把依赖的模块添加到Prism框架中进行管理.
moduleCatalog.AddModule<ModuleProfile>();
base.ConfigureModuleCatalog(moduleCatalog);
}
方式二:重写CreateModuleCatalog
方法,不需要引用模块dll
从指定目录中查找所有符合约定的程序集。将依赖的模块dll复制到该目录下。
protected override IModuleCatalog CreateModuleCatalog()
{
//查找目录中所有符合约定的程序集,添加到Prism框架中
return new DirectoryModuleCatalog() { ModulePath = @".\Modules" };
}
也可以通过配置文件app.config
实现模块化,将模块dll放置到主项目输出路径下。
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/>
</configSections>
<startup>
<supportedRuntime version="v5.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<modules>
<module assemblyFile="ModuleA.dll"
moduleType="ModuleA.ModuleProfile, ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
moduleName="ModuleProfile" startupLoaded="True" />
</modules>
</configuration>
5.导航
导航实在区域的基础上实现的,除了可以区域页面跳转外还可以实现传参, 导航确认,导航拦截,导航日志等。
(导航执行顺序)
(1)传参
主窗体通过NavigationParameters
设置参数,并通过RequestNavigate
传递给导航窗体。
void Open(string name)
{
//定义参数
NavigationParameters parameters = new NavigationParameters();
parameters.Add("Title", "我是导航A");
//像目标 name 传递参数
this.regionManager.Regions["ContentRegion"].RequestNavigate(name,parameters);
}
(2)接收参数
导航项目新增模块类,实现INavigationAware
接口。
class PageAViewModel : BindableBase, INavigationAware
{
public PageAViewModel()
{
}
private string title;
public string Title
{
get { return title; }
set { title = value; RaisePropertyChanged(); }
}
//是否重用当前实例
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return false;
}
//在当前的页面导航到其他页面的时候发生,可以用于拦截导航。
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
//导航完成前, 此处可以处理传递过来的参数以及是否允许导航等。
public void OnNavigatedTo(NavigationContext navigationContext)
{
//三种方式
if (navigationContext.Parameters.ContainsKey("Title"))
Title = navigationContext.Parameters.GetValue<string>("Title");
}
}
PageA页面:<TextBlock Text="{Binding Title}" FontSize="60"/>
(3)导航确认和拦截
实现接口由INavigationAware->IConfirmNavigationRequest
(其派生于INavigationAware,有委托类型的回调函数),并实现ConfirmNavigationRequest
方法
class PageAViewModel : BindableBase, IConfirmNavigationRequest
{
//导航确认,
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
bool result = true;
if (MessageBox.Show("是否允许进入此页面?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
{
result = false;
}
// 是否允许下一步进入某个页面**********
continuationCallback(result);
}
实现其他如IsNavigationTarget等方法
......
}
从当前页面跳转到其他页面时发生,如从PageA跳转到PageB,执行顺序:
(A)RequestNavigate->ConfirmNavigationRequest->OnNavigatedFrom->(B)IsNavigationTarget->PageBViewModel(若重用实列)->OnNavigatedTo
(4)导航日志
声明一个IRegionNavigationJournal
,它包含导航日志相关的API。
public class MainViewModel : BindableBase
{
private readonly IRegionManager regionManager;
private IRegionNavigationJournal journal;
public DelegateCommand<string> OpenCommand { get; private set; }
public DelegateCommand BackCommand { get; private set; }
public DelegateCommand NextCommand { get; private set; }
public MainViewModel(IRegionManager regionManager)
{
OpenCommand = new DelegateCommand<string>(Open);
BackCommand = new DelegateCommand(Back);
NextCommand = new DelegateCommand(Next);
this.regionManager = regionManager;
}
//GoBack返回(),GoForward()前进,Clear()清空日志
private void Back()
{
if (journal.CanGoBack)
journal.GoBack();
}
private void Go()
{
if (journal.CanGoForward)
{
journal.GoForward();
}
}
void Open(string name)
{
NavigationParameters parameters = new NavigationParameters();
parameters.Add("Title", name);
//通过regionManager接口获取当前全局定义的可用区域
//通过依赖注入的方式动态的往这个区域注入内容
this.regionManager.Regions["ContentRegion"].RequestNavigate(name, callback =>
{
if ((bool)callback.Result)//导航成功
{
journal = callback.Context.NavigationService.Journal;//存储导航请求记录
}
}, parameters);
}
}
标签:regionManager,框架,void,private,Prism,导航,public,页面
From: https://www.cnblogs.com/xixi-in-summer/p/17983070