文章目录

  • 前言
  • Prism基本使用
    • Prism选择,DryIoc还是Unity
    • Prism基本框架搭建
    • Prism动态更新
      • View和ViewModel对应关系
      • 参数动态更新
      • 函数动态绑定
    • prism新建项目模板
    • region
      • 使用事例
      • 测试是否限制空间
    • 消息订阅
      • 如何使用消息订阅
      • 使用建议
    • 路由导航
    • 对话框/弹窗功能
      • 实现代码

前言

Prims框架是WPF的一个框架,特点是集成了我们平常常用的开发模式,封装了很多常用的功能。例如消息通知,路由导航,Model绑定。

Prism基本使用

资料来源

WPF-Prism8.0核心教程(公益)

Prism选择,DryIoc还是Unity

根据网上的说明,DryIoc是更加效率更高的,但是我看Nuget下载数量里面,Unity下载数量比DryIoc高得多。具体没怎么用过,那就按照推荐用DryIoc好了。

Unity和DryIoc之间性能比较

Prism基本框架搭建


在App.xaml里面,修改

App.xaml.cs

/// /// 继承prism的PrismApplication类/// public partial class App : PrismApplication{//设置启动页protected override Window CreateShell(){//启动页为MainWindowreturn Container.Resolve<MainWindow>();}protected override void RegisterTypes(IContainerRegistry containerRegistry){}}

App.xaml

<prism:PrismApplication x:Class="PrismTest.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:PrismTest"xmlns:prism="http://prismlibrary.com/"></prism:PrismApplication>

Prism动态更新

View和ViewModel对应关系


View和ViewModel可以自动绑定,命名要求为。

  • Model:NameViewModel
  • View:Name/NameView(两者都可以)
    在View中添加入如下代码
xmlns:prism引入命名空间prism:ViewModel设置自动绑定可以不加,默认进行了绑定。<Window ...xmlns:prism="http://prismlibrary.com/"prism:ViewModelLocator.AutoWireViewModel="True">

也可以在App.xaml里面强行绑定

在原文件件中取消绑定

app.xaml

/// <summary>/// 路由管理/// </summary>/// <param name="containerRegistry"></param>protected override void RegisterTypes(IContainerRegistry containerRegistry){//通过RegisterForNavigation进行强行绑定,强行让ViewA和ViewAViewModel进行绑定containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();}

参数动态更新

//继承BindableBase接口public class MyListBoxItem : BindableBase{private string text;public string Text{get { return text; }set {SetProperty(ref text, value);}//此方法为Prism提供}}

可以输入propp加tab键,模板输入,提交写代码效率

函数动态绑定

函数动态绑定需要用到委托类型,如果委托不明白需要自己回去了解一下

viewModel

//声明委托public DelegateCommand TestBtn { get; set; }//构造函数public MainWindowViewModel(){//实例化委托TestBtn = new DelegateCommand(() =>{//执行内容});}

view

使用Command引用委托,如果没有TestBtn委托也不报错<Button Content="测试方法"FontSize="100"Grid.Row="1"Command="{Binding TestBtn}"/>

prism新建项目模板

在扩展,管理扩展中安装

我们在新建程序的时候会有Prism模板框架

使用时会提示使用什么容器,这里推荐DryIoc容器

新建文件路径如下

region

Prism将界面继续划分,分为多个Region,在Region中添加元素。

和WPF用户组件的区别。

  • Region相当于划分了空区域,WPF是有内容的区域。
  • Region相当于WPF用户控件的上级,用于包含用户控件

使用事例

MainWindow.xaml

<Grid><ContentControl prism:RegionManager.RegionName="ContentRegion" /></Grid>

UserControl1.xaml,用于放置在Region上面的用户控件

<Grid><TextBlockText="我是用户控件" FontSize="100"/></Grid>

MainWindowViewModel.xaml

//注册regionManager控件private readonly IRegionManager _regionManager;public MainWindowViewModel(IRegionManager regionManager){this._regionManager = regionManager;//ContentRegion是窗口已声明的Region,使用字符串进行弱绑定regionManager.RegisterViewWithRegion("ContentRegion",typeof(UserControl1));}

生成效果

测试是否限制空间

<Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><ContentControl prism:RegionManager.RegionName="ContentRegion" /></Grid>

实现效果

消息订阅

消息订阅是先订阅再发布有效,如果是先发布再订阅则无效。

如何使用消息订阅

 public class MainWindowViewModel : BindableBase{private string _title = "Prism Application";//声明委托public DelegateCommand TestBtn { get; set; }public DelegateCommand SendCommand { get; set; }private readonly IEventAggregator _eventAggregator;public string Title{get { return _title; }set { SetProperty(ref _title, value); }}//构造函数public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator){//实例化委托//订阅TestBtn = new DelegateCommand(() =>{eventAggregator.GetEvent<MessageEvent>().Subscribe(OnMessageRecevied);});//发送SendCommand = new DelegateCommand(() =>{//执行参数eventAggregator.GetEvent<MessageEvent>().Publish("Hello Event");});this._eventAggregator = eventAggregator;}public void OnMessageRecevied(string msg){Title += msg + "\r\n";}//消息订阅类public class MessageEvent: PubSubEvent<string> {}}

注意
eventAggregator.GetEvent()。MessageEvent是我们自己定义的,相当于订阅的消息主题。

eventAggregator.GetEvent().

  • Subscribe(OnMessageRecevied);
    • OnMessageRecevied是处理函数
  • Publish(“Hello Event”)
    • “Hello Event”是入参,因为OnMessageRecevied(string msg)

取消订阅

eventAggregator.GetEvent<MessageEvent>().Unsubscribe(OnMessageRecevied);

使用建议

  • 注意,这个是全局使用的,所以一般用于页面通讯
    • 例如:AView。我就用AViewEvent。一个页面对应一个事件通知。
  • 由于带入的参数不一定,所以我们可以设置Dictionary为入参,通过key值过滤来设置对应的函数。通过NetJson来快速传参。

路由导航

路由导航和Region是搭配使用的,专门用于页面转化

  • 新建切换用的用户控件ViewA,ViewB,ViewC。ViewA,B,C内容有区分,这里省略
  • 在App.xaml.cs中注册页面
/// /// 路由管理/// /// protected override void RegisterTypes(IContainerRegistry containerRegistry){//将ViewA,B,C添加到导航,这样才能进行路由管理containerRegistry.RegisterForNavigation<ViewA>("ViewA");containerRegistry.RegisterForNavigation<ViewB>();containerRegistry.RegisterForNavigation<ViewC>();}
  • 在MainView中添加委托事件
 <Grid><Grid.RowDefinitions><RowDefinition Height="50"/><RowDefinition /></Grid.RowDefinitions><StackPanel Orientation="Horizontal"><Button Content="ViewA"Command="{Binding OpenACommand}" /><Button Content="ViewB"Command="{Binding OpenBCommand}" /><Button Content="ViewC"Command="{Binding OpenC_Command}" /><Button Content="上一页"Command="{Binding GoBackCommand}" /><Button Content="下一页"Command="{Binding GoForwordCommand}"/></StackPanel><ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" /></Grid>

在MainiView里面管理导航

namespace PrismNavigation.ViewModels{public class MainWindowViewModel : BindableBase{private string _title = "Prism Application";public string Title{get { return _title; }set { SetProperty(ref _title, value); }}/// /// 导航日志/// private IRegionNavigationJournal _journal;//Region,用于页面切换private readonly IRegionManager _regionManager;public DelegateCommand OpenACommand { get; set; }public DelegateCommand OpenBCommand { get; set; }public DelegateCommand OpenC_Command { get; set; }public DelegateCommand GoBackCommand { get; set; }public DelegateCommand GoForwordCommand { get; set; }public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator){_regionManager = regionManager;OpenACommand = new DelegateCommand(OpenA);OpenBCommand = new DelegateCommand(OpenB);OpenC_Command = new DelegateCommand(OpenC);GoBackCommand = new DelegateCommand(GoBack);GoForwordCommand = new DelegateCommand(GoForword);}private void OpenA(){NavigationParameters para = new NavigationParameters{{ "Value", "Hello Prism" }};//进行路由传参,ContentRegion是xmal中的Region名称,ViewA是在App.xmal中注册的名称,arg是日志回调,para是路由传递的参数_regionManager.RequestNavigate("ContentRegion", "ViewA", arg =>{///获取导航日志_journal = arg.Context.NavigationService.Journal;}, para);}private void OpenB(){_regionManager.RequestNavigate("ContentRegion", "ViewB", arg =>{///获取导航日志_journal = arg.Context.NavigationService.Journal;});}private void OpenC(){_regionManager.RequestNavigate("ContentRegion", "ViewC", arg =>{///获取导航日志_journal = arg.Context.NavigationService.Journal;});}private void GoForword(){_journal.GoForward();}private void GoBack(){_journal.GoBack();}}}

在ViewA中进行路由拦截

 public class ViewAViewModel :BindableBase, IConfirmNavigationRequest{private string _name;public string Name{get { return _name; }set { SetProperty(ref _name, value); }}/// /// IConfirmNavigationRequest的路由离开拦截,/// /// /// /// public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback){var res = true;if(MessageBox.Show("确认导航?","温馨提示",MessageBoxButton.YesNo) == MessageBoxResult.No){res = false;}//如果res为true则拦截,true则放行continuationCallback" />.Invoke(res);}/// /// 用于判断是否要重新创建新的事例,即是否保留之前的信息,True为重新创建。/// /// /// /// public bool IsNavigationTarget(NavigationContext navigationContext){return true;}/// /// 离开页面时触发,一般用于取消事件监听/// /// /// public void OnNavigatedFrom(NavigationContext navigationContext){}/// /// 显示页面前触发,一般用于设置事件监听/// /// /// public void OnNavigatedTo(NavigationContext navigationContext){//拿到Key为Value的值,返回类型为stringName = navigationContext.Parameters.GetValue<string>("Value");}}

实现效果

简单介绍

  • 路由导航是Region导航,必须要先将WPF用户控件添加到Region中才能进行导航
  • 在注册时,可以添加别名
    • containerRegistry.RegisterForNavigation(“别名”);
_regionManager.RequestNavigate("ContentRegion", "别名");//原本是ViewA的,可以替换成别名

对话框/弹窗功能

Prism将对话框这个常用的功能进行了封装。虽然叫对话框,但其实是弹窗的功能效果。

实现代码

app.xaml中

/// /// 路由管理/// /// protected override void RegisterTypes(IContainerRegistry containerRegistry){.......//这里也能起别名containerRegistry.RegisterDialog<MsgView,MsgViewModel>("别名"); }

MainViewModel使用这个弹窗

public class MainWindowViewModel : BindableBase{private string _title = "Prism Application";public string Title{get { return _title; }set { SetProperty(ref _title, value); }}/// /// 导航日志/// private IRegionNavigationJournal _journal;private readonly IRegionManager _regionManager;//注册弹窗服务private IDialogService _dialogService;public DelegateCommand OpenACommand { get; set; }//构造函数中传入对话框public MainWindowViewModel(IRegionManager regionManager,IEventAggregator eventAggregator,IDialogService dialogService){_regionManager = regionManager;OpenACommand = new DelegateCommand(OpenA);GoForwordCommand = new DelegateCommand(GoForword);//使用对话框_dialogService = dialogService;}private void OpenA(){//对话框传递的参数DialogParameters param = new DialogParameters();param.Add("Value", "paramTest");//打开名为MsgView的弹窗,并传递参数_dialogService.Show("MsgView", param, arg =>{//弹窗关闭的回调函数,会有参数返回if(arg.Result == ButtonResult.OK){Debug.WriteLine("调试成功");}});}}

MsgView

<Grid Background="White"><Grid.RowDefinitions><RowDefinition Height="30" /><RowDefinition /><RowDefinition Height="50"/></Grid.RowDefinitions><TextBox Grid.Row="1" Text="{Binding Title}" FontSize="20"/><Label Content="{Binding Title}"/><DockPanel Grid.Row="2" LastChildFill="False"><Button Content="取消" Width="60"DockPanel.Dock="Right"Command="{Binding CancelCommand}" /><Button Content="确定"Width="60"DockPanel.Dock="Right"Command="{Binding SaveCommand}"/></DockPanel></Grid>
public class MsgViewModel :BindableBase, IDialogAware{private string _title;public string Title{get { return _title; }set { SetProperty(ref _title, value); }}/// /// 用于弹窗关闭的回调函数/// public event Action<IDialogResult> RequestClose;public DelegateCommand SaveCommand { get; set; }public DelegateCommand CancelCommand { get; set; }public MsgViewModel() {SaveCommand = new DelegateCommand(() =>{DialogParameters keyValuePairs = new DialogParameters();keyValuePairs.Add("Value", Title);//执行弹窗关闭,并传入回调参数RequestClose" />.Invoke(new DialogResult(ButtonResult.OK, keyValuePairs));});CancelCommand = new DelegateCommand(() =>{RequestClose?.Invoke(new DialogResult(ButtonResult.No));});}/// /// 能否打开窗口/// /// public bool CanCloseDialog(){return true;}/// /// 关闭的方法/// /// public void OnDialogClosed(){//throw new NotImplementedException();}/// /// 打开之前,接受弹窗传参/// /// /// public void OnDialogOpened(IDialogParameters parameters){Title = parameters.GetValue<string>("Value");}}