文章目录
- 前言
- 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");}}