【WPF】Prism框架基础
Prism框架:
初识:
我们创建一个基于net5.0的WPF应用程序
创建完之后在VS里面添加相关的包
修改app继承的基类
public partial class App : PrismApplication
{
}
这时候会报错,我们去修改前台的代码
<prism:PrismApplication x:Class="PrisimDemo.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:PrisimDemo"xmlns:prism="http://prismlibrary.com/"><Application.Resources></Application.Resources>
</prism:PrismApplication>
修改完并保存之后我们重新生成一下解决方案
重新生成项目之后我们需要实现基类PrismApplication的方法
public partial class App : PrismApplication{//这个方法要返回一个Window,我们直接通过Container容器返回我们的主窗体//在App.xaml文件中,不再设置StartupUriprotected override Window CreateShell(){return Container.Resolve<MainWindow>();}//第二个方法实现了依赖注入的功能 一开始我们没有就不添加了protected override void RegisterTypes(IContainerRegistry containerRegistry){}}
}
这样就将我们创建的一个默认的WPF应用程序改造成基于Prism框架的程序了
我们启动一下,如果弹出两个框说明app中的starturl那一行没有删除
那么上述方法还是有些繁琐的,每次创建一个新项目就要修改很多东西,我们去扩展中下载一个模板
tips: vs2019下载扩展时,会出现下载失败的情况,可用电脑连接手机热点下载
下载完之后我们重新启动一下VS2019
安装完毕之后我们重新启动VS,并创建一个新项目
默认官方提供的容器有DryIoc和unity,我们选择DryIoc就行
进入项目我们可以看到FullApp1中app.xaml中与我们之前自己手动修改的代码一样,设置FullApp1为启动项目,启动后我们就可以看到
区域介绍:
为了引入区域的概念我们先来使用我们第一个创建的项目,并实现点击按钮切换按钮下面内容的功能
先布好局
<Grid><Grid.RowDefinitions><RowDefinition Height="auto"></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><StackPanel Orientation="Horizontal"><Button Margin="5" Content="打开模块A" Command="{Binding OpenCommand}" CommandParameter="ViewA"></Button><Button Margin="5" Content="打开模块B" Command="{Binding OpenCommand}" CommandParameter="ViewB"></Button><Button Margin="5" Content="打开模块C" Command="{Binding OpenCommand}" CommandParameter="ViewC"></Button></StackPanel><ContentControl Grid.Row="1" Content="{Binding Body}"></ContentControl></Grid>
创建一个Views文件夹,里面创建三个View,分别是ViewA,ViewB,ViewC
<TextBlock FontSize="80" Text="我是模块A"></TextBlock>
为了实现切换功能我们创建一个ViewModels文件夹,里面创建一个MainViewModel类
public class MainViewModel : BindableBase{public DelegateCommand<string> OpenCommand { get; private set; }public MainViewModel(){OpenCommand = new DelegateCommand<string>(Open);}private Object body;public Object Body{get { return body; }set { body = value; RaisePropertyChanged(); }}private void Open(string obj){switch (obj){case "ViewA": Body = new ViewA(); break;case "ViewB": Body = new ViewB(); break;case "ViewC": Body = new ViewC(); break;}}}
这样就实现了数据和命令的绑定,但是我们没有给MainWindows添加上下文DataContext,我们可以利用Prism自动绑定上下文。但是这两个名字要有对应的关系MainView和MainViewModel,按照Prism的标准我们给MainWindow改名为MainView,在对应的地方都将MainWindow改为MainView。并且在前台上添加代码
xmlns:prism="http://prismlibrary.com/"prism:ViewModelLocator.AutoWireViewModel="True"
<Window x:Class="PrisimDemo.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:PrisimDemo"xmlns:prism="http://prismlibrary.com/"mc:Ignorable="d"Title="MainView" Height="450" Width="800"prism:ViewModelLocator.AutoWireViewModel="True"><Grid><Grid.RowDefinitions><RowDefinition Height="auto"></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><StackPanel Orientation="Horizontal"><Button Margin="5" Content="打开模块A" Command="{Binding OpenCommand}" CommandParameter="ViewA"></Button><Button Margin="5" Content="打开模块B" Command="{Binding OpenCommand}" CommandParameter="ViewB"></Button><Button Margin="5" Content="打开模块C" Command="{Binding OpenCommand}" CommandParameter="ViewC"></Button></StackPanel><ContentControl Grid.Row="1" Content="{Binding Body}"></ContentControl></Grid>
</Window>
但是这么做我们发现我们这样写代码的耦合性太高,仅仅实现这样一个简单的功能MainVIewModel就有一长段代码了,我们就使用Region来解决这个问题。
在前台删除ContentControl的绑定数据并指定一个RegionName
代表我们给中间这一块区域定义了一个名字
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="COntentRegion"></ContentControl>
我们就可以在MainViewModel里通过IRegionManager拿到我们上面定义的Region区域
namespace PrisimDemo.ViewModels
{public class MainViewModel : BindableBase{private readonly IRegionManager regionManager;public DelegateCommand<string> OpenCommand { get; private set; }public MainViewModel(IRegionManager regionManager){OpenCommand = new DelegateCommand<string>(Open);this.regionManager = regionManager;}private void Open(string obj){//首先通过IRegionManager接口获取全局定义可用区域//往这个区域动态设置内容//设置内容的方式是通过依赖注入的形式regionManager.Regions["ContentRegion"].RequestNavigate(obj);}}
}
我们怎么通过一个字符串俩获取在区域内设置的内容就要靠之前在app文件中的依赖注入。
//第二个方法实现了依赖注入的功能 一开始我们没有就不添加了protected override void RegisterTypes(IContainerRegistry containerRegistry){//在这里面注册ViewA,B,C,括号里面的是别名containerRegistry.RegisterForNavigation<ViewA>();containerRegistry.RegisterForNavigation<ViewB>();containerRegistry.RegisterForNavigation<ViewC>();}
这样就修改好了之前的代码,可以发现比之前简洁很多!
模块化
我们的功能模块不一定写在一个项目当中,我们往往会分为多个模块来进行开发。我们修改前面的代码,将View文件夹中的ViewA和ViewB删掉。给解决方案添加两个项目粉分别为ModuleA和ModuleB,并在这两文件夹里面添加Views文件夹,里面分别存放ViewA.xaml和ViewB.xaml
我们还要将这两个View注册到容器中,然后再将这两个Module添加到主窗体中,理论上就实现了模块化的功能。
首先我们给两个Module在依赖里面添加对Prism.DryIoc的支持,安装完毕之后给两个Module分别添加类ModuleAProfile与ModuleBProfile
namespace ModuleA
{public class ModuleAProfile : IModule{public void OnInitialized(IContainerProvider containerProvider){}public void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterForNavigation<ViewA>();}}
}
接下来就是去主窗体的app文件中修改代码,首先我们删除Views文件夹中的ViewA,ViewB和ViewC
在主程序中引用相应的模块
给app文件重写ConfigureModuleCatalog方法,利用ModuleAProfile和ModuleBProfile将两个模块的内容添加到主程序中
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog){moduleCatalog.AddModule<ModuleAProfile>();moduleCatalog.AddModule<ModuleBProfile>();base.ConfigureModuleCatalog(moduleCatalog);}
这样就是实现了模块化,可以发现ModuleA与ModuleB完全与主程序分离出来了
导航功能
我们之前就通过导航实现了各个模块之前的切换
private void Open(string obj){//首先通过IRegionManager接口获取全局定义可用区域//往这个区域动态设置内容//设置内容的方式是通过依赖注入的形式regionManager.Regions["ContentRegion"].RequestNavigate(obj);}
如果我们想要模块支持导航功能我们就必须在容器中去注册这个模块
之前我们是通过Prism自动匹配页面的上下文,我们也可以在注册的时候手动配置,一般我们都不使用自动匹配
containerRegistry.RegisterForNavigation<ViewA,ViewAViewModel>();
当我们导航到ViewA时,我们可以传递一些参数
private void Open(string obj){//通过字典来传递参数NavigationParameters keys = new NavigationParameters();keys.Add("Title", "Hello");//首先通过IRegionManager接口获取全局定义可用区域//往这个区域动态设置内容//设置内容的方式是通过依赖注入的形式regionManager.Regions["ContentRegion"].RequestNavigate(obj,keys);}
我们在VIewAViewModel中实现INavigationAware来接收参数
创建ViewA的上下文ViewAViewModel
namespace ModuleA.ViewModels
{public class ViewAViewModel : BindableBase, IConfirmNavigationRequest{public ViewAViewModel(){}private string title;public string Title{get { return title; }set { title = value; RaisePropertyChanged(); }}//每次重新导航的时候 该实例是否重用原来的实例public bool IsNavigationTarget(NavigationContext navigationContext){return true;}//拦截导航请求public void OnNavigatedFrom(NavigationContext navigationContext){}//接受参数public void OnNavigatedTo(NavigationContext navigationContext){if(navigationContext.Parameters.ContainsKey("Title"))Title = navigationContext.Parameters.GetValue<string>("Title");}//验证是否允许切换public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback){bool result = true;if (MessageBox.Show("确认导航?", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.No){result = false;}continuationCallback(result);}}
}
修改前台代码,让Title显示出来
<TextBlock Text="{Binding Title}" FontSize="80" ></TextBlock>
导航还能实现返回上一页下一页的功能
这里面涉及到导航日志的概念
我们在主程序前台上添加一个返回上一页的按钮
<Button Margin="5" Command="{Binding BackCommand}" CommandParameter="ViewB" Content="返回上一步"></Button>
修改MainViewModel 的代码
namespace PrisimDemo.ViewModels
{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 MainViewModel(IRegionManager regionManager){OpenCommand = new DelegateCommand<string>(Open);BackCommand = new DelegateCommand(Back);this.regionManager = regionManager;}private void Back(){//上一步if(journal.CanGoBack)journal.GoBack();}private void Open(string obj){NavigationParameters keys = new NavigationParameters();keys.Add("Title", "Hello");//首先通过IRegionManager接口获取全局定义可用区域//往这个区域动态设置内容//设置内容的方式是通过依赖注入的形式regionManager.Regions["ContentRegion"].RequestNavigate(obj,callBack=> {//我们每次导航都会有一个回调,我们可以通过回调的结果来获取导航日志if ((bool)callBack.Result){journal = callBack.Context.NavigationService.Journal;}}, keys);}}
}
这样就实现了返回上一页的功能!
对话服务
简单点讲就是封装好的弹窗的API
我们在ViewAModule模块下的Views里面新建一个ViewC用户控件
<Grid><Grid.RowDefinitions><RowDefinition Height="auto"></RowDefinition><RowDefinition Height="auto"></RowDefinition><RowDefinition Height="auto"></RowDefinition></Grid.RowDefinitions><TextBlock Text="温馨提示?"></TextBlock><TextBlock Text="{Binding Title}" Grid.Row="1" VerticalAlignment="Center" FontSize="80"></TextBlock><StackPanel Grid.Row="2" Orientation="Horizontal"><Button Content="确定" Command="{Binding SaveCommand}" Height="80" Width="100"></Button><Button Content="取消" Command="{Binding CancelCommand}" Height="80" Width="100"></Button></StackPanel></Grid>
然后将VIewC绑定到容器中
public void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterDialog<ViewC,ViewCViewModel>();containerRegistry.RegisterForNavigation<ViewA,ViewAViewModel>();}
我们还要配置ViewC的上下文,创建ViewCViewModel并是实现IDialogAware这个类
namespace ModuleA
{public class ViewCViewModel : IDialogAware{public ViewCViewModel(){CancelCommand = new DelegateCommand(Cancel);SaveCommand = new DelegateCommand(Save);}private void Cancel(){RequestClose?.Invoke(new DialogResult(ButtonResult.No));}private void Save(){OnDialogClosed();}public string Title { get; set; }public DelegateCommand CancelCommand { get; set; }public DelegateCommand SaveCommand { get; set; }public event Action<IDialogResult> RequestClose;//是否允许关闭public bool CanCloseDialog(){return true;}public void OnDialogClosed(){DialogParameters keys = new DialogParameters();keys.Add("Value", "111111");//返回的结果 名字为Value的变量值为关闭RequestClose?.Invoke(new DialogResult(ButtonResult.OK, keys));}public void OnDialogOpened(IDialogParameters parameters){//接受传递过来的参数Title = parameters.GetValue<string>("Title");}}
}
在MainViewModel中
namespace PrisimDemo.ViewModels
{public class MainViewModel : BindableBase{private readonly IDialogService dialogService;public MainViewModelIDialogService dialogService){this.dialogService = dialogService;}private void Open(string obj){//传递过去的参数DialogParameters keys = new DialogParameters();keys.Add("Title", "Hello·······");dialogService.ShowDialog(obj,keys,callback=>{//接受回调过来的参数if (callback.Result == ButtonResult.OK){string result = callback.Parameters.GetValue<string>("Value");}});}}
}
发布订阅功能
实现了发送消息的功能,我们在view或者viewmodel中发布消息那么在view或者viewmodel只要订阅了这个消息都可以接收到发送过来的消息。
例:我们在ModuleA中新建一个Event文件夹在里面创建一个MessageEvent类
public class MessageEvent:PubSubEvent<string>
{
}
MessageEvent这个类继承了PubSubEvent就是一个string类型的消息模型
我们在ViewCViewModel中向MessageEvent发布一个消息
private readonly IEventAggregator aggregator;public ViewCViewModel(IEventAggregator aggregator){CancelCommand = new DelegateCommand(Cancel);SaveCommand = new DelegateCommand(Save);this.aggregator = aggregator;}private void Cancel(){//向MessageEvent 发布一个helloaggregator.GetEvent<MessageEvent>().Publish("Hello");// RequestClose?.Invoke(new DialogResult(ButtonResult.No));}
我们在ViewC中接受这个消息
public ViewC(IEventAggregator aggregator){InitializeComponent();aggregator.GetEvent<MessageEvent>().Subscribe(arg =>{MessageBox.Show("接收到了" + arg);});}
这样就实现了发布订阅的功能,同时也可以取消订阅
public ViewC(IEventAggregator aggregator){InitializeComponent();aggregator.GetEvent<MessageEvent>().Subscribe(SubMessage);aggregator.GetEvent<MessageEvent>().Unsubscribe(SubMessage);}private void SubMessage(string obj){MessageBox.Show("接受到了" + obj);}
我们也可以定义一个复杂消息模型
public class TestEvent : PubSubEvent<Test>
{}public class Test
{public string Id { get; set; }public string Name { get; set; }
}
【WPF】Prism框架基础相关推荐
- WPF Prism框架
Prism框架 1.关于Prism框架 官方地址:http://prismlibrary.com 官方源码:https://github.com/PrismLibrary/Prism 版本 ...
- WPF Prism框架之Dialog
基本用法 1.添加一个用户控件(作为弹出窗口的内容)->进行注册RegisterDialog 2.添加对应的ViewModel->实现IDialogAware接口 3.通过注入的IDial ...
- C# WPF MVVM模式Prism框架从零搭建(经典)
01 - 前言 目前最新的PRISM的版本是8.1.97,本节以6.3.0.0 讲解,可以在Github上获取PRISM的源码. Prism Github地址:https://github.com/P ...
- WPF的Prism框架简介
什么是Prism Prism是一个用于在 WPF.Xamarin Form.Uno 平台和 WinUI 中构建松散耦合.可维护和可测试的 XAML 应用程序框架. Prism是一个用于在WPF.Xam ...
- WPF(七) Prism框架基本特性
参考文档: Prism 官方文档 Prism Library Prism GitHub 地址 GitHub - PrismLibrary/Prism 大佬博客 Prism合集 - 随笔分类 - 痕迹g ...
- Prism框架(一)——概述Prism框架的设计目的是用来帮助构建丰富、灵活、易维护的WPF和Si...
Si Prism框架(一)--概述Prism框架的设计目的是用来帮助构建丰富.灵活.易维护的WPF和Si 提问者:mfksnr120(ID:187460) | 悬赏 0.0 希赛币 | 回答数:0 | ...
- .NET Core 3 WPF MVVM框架 Prism系列之事件聚合器
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器 在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...
- c#事件的发布-订阅模型_NET Core 3 WPF MVVM框架 Prism系列之事件聚合器
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的使用事件聚合器实现模块间的通信 一.事件聚合器# 在上一篇 .NET Core 3 WPF MVVM框架 Prism系列之模块化 ...
- prism项目搭建 wpf_WPF Step By Step 系列-Prism框架在项目中使用
Prism是一个强大的Mvvm框架,下面我们将重点讲解如何在项目使用Prism提供的基础功能,完成基于MVVM的WPF项目的框架设计和开发,包括应用程序的架构. 项目的解决方案结构,项目采用Prism ...
最新文章
- HTC VIVE SDK 中的例子 hellovr_opengl 程序流程分析
- RHEL 6.x 搭建企业级FTP
- oracle11g安装到第7步,centos7安装oracle11g到这一步卡在了?也没有安装界面
- AddOutParameter引发类型问题
- 【xml】利用OpenCV解析
- 微型计算机的普通显示器通常有两组引线 即,微型计算机的显示屏通常具有两组引线,即()...
- XP命令合集(开始→运行→输入的命令集锦开始→运行→输入的命令集锦)
- 3个概念,入门 Vue 组件开发
- 小学学校计算机室文化建设方案,计算机室文化建设方案
- android窗口变化事件,android ViewPager滑动事件讲解
- 希尔伯特变换求包络原理
- 如何触发‘isTrusted = true‘点击事件
- FL Studio 蜕变发展史及FL Studio21如何带你进入AI编曲时代
- 神州信息“六合上甲”一体化数据开发平台全面数智升级!
- MouseJack:利用15美元的工具和15行代码控制无线鼠标和键盘
- 51nod 1326 遥远的旅途 最短路建模
- 我为什么要进国企——HP大中华区总裁孙振耀退休感言
- 力扣动态规划入门21天刷题计划(共计46题)
- 《国际结算》期末试卷及参考答案
- 城市路网中心线及面积计算等