二十五、Prism框架

1、Prism的概念,应用场景

  • Modules:Modules是能够独立开发、测试、部署的功能单元,Modules可以被设计成实现特定业务逻辑的模块(如Profile Management),也可以被设计成实现通用基础设施或服务的模块(如Logging、Exception Management)。
  • ModuleCatalog:在Prism中,Module Catalog指明了要Load哪些Module,和用什么样的顺序去Load这些Module。
  • Shell:Shell是宿主应用程序(host application),modules将会被load到Shell中。Shell定义了应用程序的整体布局和结构,而不关心寄宿其中的Module,Shell通常实现通用的application service和infrastructure,而应用的逻辑则实现在具体的Module中,同时,Shell也提供了应用程序的顶层窗口。
  • Views:Views是应用中展现特定功能的视图,它展现UI、定义交互行为,并且通过数据绑定的方式与ViewModel进行交互。
  • ViewModelPresenters:View Model用来封装应用程序的UI逻辑及其状态。
  • Model:Model被用来封装数据和相应的验证,以及相关的业务规则来保证数据的一致性和正确性。
  • Commands:Command被用来封装应用程序功能,Prism提供了DelegateCommandCompositeCommand两个类。
  • Regions(区域):Regions是应用程序UI的逻辑区域,它很像一个PlaceHolder,Views在Regions中展现,很多种控件可以被用作Region:ContentControl、ItemsControl、ListBox、TabControl。Views能在Regions编程或者自动呈现,Prism也提供了Region导航的支持。


2、Prism使用过程(PrismApplication,Prism项目模板),Prism实现Mvvm(BindableBase,RaisePropertyChanged(),DelegateCommand,SetProperty())

创建Prism项目时可以先创建WPF,然后修改App.xaml内容。也可以使用项目模板,需要在拓展中安装"Prism Tempalte Pack",然后创建新项目时,选择Prism Full App(WPF)项目即可:

二十五、Prism框架_第1张图片

下面一个WPF修改成Prism项目为例,简单使用Prism项目: 

  • 创建WPF窗体项目

二十五、Prism框架_第2张图片

  •  下载prism.Dryioc依赖包

  •  在App.xaml命名空间中添加prism依赖:xmlns:prism="http://prismlibrary.com/"。将App.xaml文件中的Application标签修改成为 prism:PrismApplication  。(wfp项目应用的是Application对象,使用prism框架的项目应用的是PrismApplication。Application对象如何启动主页面, StartupUri, PrismApplication启动主页面可以靠StartupUri(可删去),也可不需要,推荐使用App .xaml.cs中CreateShell()方法中的依赖注入)

    
    

  • 创建Views和ViewModels文件夹,将项目创建时自动创建的MainWindow.xaml视图文件,移动到Views文件夹下(别忘了修改MainWindow.xaml和MainWindow.xaml.cs中的命名空间,要加上.Views)

修改为:
  • 修改App.xaml.cs继承的类,将继承的Window类改成PrismApplication类,实现PrismApplication类中的CreateShell()方法和RegisterTypes()方法
namespace PrismDemo
{
    /// 
    /// App.xaml 的交互逻辑
    /// 
    public partial class App : PrismApplication
    {
        // 关系:PrismApplication 继承于 PrismApplicationBase 继承于 Application
        // 快捷键:查看对象源码:fn+f12,快速实现接口,方法,抽象类:alt+enter+enter
        // 快速创建构造函数:ctor

        // Window窗体, StartupUri可以启动一个窗体
        // CreateShell()主要负责启动一个主页面。Main
        protected override Window CreateShell()
        {
            // 启动一个窗体MainWindow
            return Container.Resolve
(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { } } }
  • 页面:

点击更改Name按钮后,会与mvvm框架实现效果一样,修改文本框名字,实现视图和后台修改时数据交互。

二十五、Prism框架_第3张图片

  • MainWindow.xaml视图中测试代码编写:

    
        

        
            
            
            
  •  MainWindow.xaml.cs的DataContext绑定ViewModel类中编写的数据
namespace PrismDemo.Views
{
    /// 
    /// Main.xaml 的交互逻辑
    /// 
    public partial class MainWindow : Window
    {
        MainWindowViewModel viewModel = new MainWindowViewModel();

        public Main()
        {
            InitializeComponent();
            // 把ViewModel和当前窗体MainWindow建立联系
            // 只能保证:ViewModel提供的数据源可以在xaml视图上使用。
            DataContext = viewModel;
        }
    }
}
  •  MainWindowViewModel.cs中代码:

Prism.Mvvm中的BindableBase 相当于CommunityToolkit.Mvvm中的ObservableObject 

Prism.Mvvm.BindableBase中的RaisePropertyChanged()相当于CommunityToolkit.Mvvm中的ObservableObject.OnPropertyChanged() 。和视图数据交互的还可以使用SetProperty(ref _title, value);实现

Prism.Commands.DelegateCommand ===> CommunityToolkit.Mvvm中的RelayCommand

namespace PrismDemo.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        // DelegateCommand 
        public DelegateCommand ChangeNameCommand { get; private set; }
        public MainWindowViewModel()
        {
            Name = "张三";

            ChangeNameCommand = new DelegateCommand(ChangeName);
        }

        private void ChangeName(string obj)
        {
            Name = obj;
        }

        private string name;

        public string Name
        {
            // 通过BindableBase.RaisePropertyChanged()可以保证xaml视图上数据变化,通知ViewModel, 重新渲染到视图。
            get { return name; }
            //set { name = value; RaisePropertyChanged(); }
            set { SetProperty(ref name, value); }   
        }
    }
}

3、自动绑定ViewModel

  • 实现数据自动绑定(不在视图.xaml.cs中使用this.DataContent绑定)需要满足三条要求
    • 窗体|页面|用户控件必须放到Views文件夹下
    • 模型必须放到ViewModels文件夹下
    • 模型名称的名称,必须是窗体名称开头,且以ViewModel结尾
  • 满足以上三条,不需要XXX.xaml.cs中手动绑定DataContext,实现自动绑定ViewModel。

如下图目录结构:

二十五、Prism框架_第4张图片

 4、Prism区域(负责管理视图中所有定义的区域),实现简单页面点击导航展示新页面

二十五、Prism框架_第5张图片

  参考上面第3部分,创建WPF项目,将项目改成Prism项目,需要修改如下:

  • App.xaml.cs中重写的RegisterTypes()方法中,将导航点击展示需要展示的子窗体,注册进项目(以便在主页面按钮点击时给ContentControl控件使用prism:RegionManager.RegionName="RegionName"绑定后台设置控件内容的操作)。
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
      containerRegistry.RegisterForNavigation();
      containerRegistry.RegisterForNavigation();
}
  • Main.xml视图:

需要引入prism的命名依赖:xmlns:prism="http://prismlibrary.com/",以供控件使用。 ContentControl 只能展示用户控件窗体


    
        
            
            
        

        
            

二十五、Prism框架_第6张图片

  • PageA.xaml视图:

    
        
    

二十五、Prism框架_第7张图片

  •  PageB.xaml视图:

    
        
    

二十五、Prism框架_第8张图片

  • MainViewModel.cs需要继承BindableBase,在构造函数中注入IRegionManager,才能使用区域块Regions调用在App.xaml.cs中RegisterTypes()方法中注册的用户控件子窗体,实现跳转到主窗体中的ContentControl控件中。
namespace ModelDemo.ViewModels
{
    public class MainViewModel:BindableBase
    {
        private readonly IRegionManager regionManager;

        public DelegateCommand ChangeCommand { set; get; }

        //构造函数里注入IRegionManager类,调用对象才能使用区域块跳转窗体
        public MainViewModel(IRegionManager region)
        {
            ChangeCommand = new DelegateCommand((param) =>
            {
                regionManager.Regions["RegionName"].RequestNavigate(param);
            });
            this.regionManager = region;
        }
    }
}

 5、Prism模块化

        模块化的意思就是,将上面4中的PageA和PageB页面拆分出去,单独封装为类库模块,在主程序中调用这两个模块,实现导航栏页面展示。

二十五、Prism框架_第9张图片

模块类库创建步骤: 

  1. WPF类库项目(也可以用WPF(.Net Framework)应用程序---点击项目属性---改成类库项目)
  2. 每个模块都要安装程序包Prism.DryIoc
  3. 按约定编写每个模块库的Views(视图使用用户控件才能在主程序的中使用本模块的视图)和ViewModels(没有视图操作可以不写)
  4. 每个模块库都要创建配置文件XXXProfile配置文件,实现IMoudle接口,并在实现的RegisterTypes()方法中注册该页面。
  5. 注意: containerRegistry.RegisterForNavigation();  没有对视图操作的可以不用写PageAViewModel参数。例如下面MoudelA的MoudelAProfile配置文件:
namespace ModuleA
{
    public class ModuleAProfile : IModule
    {
        public void OnInitialized(IContainerProvider containerProvider)
        {
            
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // 注册用户控件,让这个模块的用户控件视图将来在主程序中可以实现导航跳转
            // RegisterForNavigation<视图,视图模型>
            containerRegistry.RegisterForNavigation();
        }
    }
}

主程序添加模块步骤:

1.创建WPF(.Net Framework)应用程序项目,将这个项目改成Prism项目。

2.按照约定创建Views和ViewModels文件夹存放视图和视图模型。

3.App.xaml.cs中通过重写ConfigureModuleCatalog()方法,将创建的模块库添加进主程序:

namespace ModuleMain
{
    /// 
    /// App.xaml 的交互逻辑
    /// 
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve
(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { } //=== 方式1: ConfigureModuleCatalog配合Profile(IModule) // 需要在主项目中把依赖的两个模块库ModuleA和ModuleB的dll依赖引入 // ConfigureModuleCatalog()主要负责把依赖的两个模块添加到Prism框架中进行管理. protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule(); moduleCatalog.AddModule(); base.ConfigureModuleCatalog(moduleCatalog); } //===方式2: ModuleMain项目完全不依赖ModuleA和ModuleB,完全解耦。 //在当前项目的bin/debug目录下新建一个Modules文件夹将模块ModuleA、ModuleB的dll复制到此文件夹下,然后下面代码里设置查找改文件夹即可 //protected override IModuleCatalog CreateModuleCatalog() //{ // return new DirectoryModuleCatalog() { ModulePath = @".\Modules" }; //} //===方式3:通过配置文件app.config实现模块化,提醒:需要把ModuleA.dll和ModuleB.dll放到主项目的bin/debug文件夹中 //protected override IModuleCatalog CreateModuleCatalog() //{ // return new ConfigurationModuleCatalog(); //} } }

4.主视图中引用命名依赖:xmlns:prism="http://prismlibrary.com/"。定义区域块:prism:RegionManager.RegionName="ContentRegion"/>,用来实现用户控件跳转展示


    
        
            
            
        

        
            

5.MainViewModel主程序中视图模型中:

        如果需要后台和视图数据交互时,视图模型就需要继承BindableBasea类,在字段的set里就可以编写:RaisePropertyChanged()实现交互。

namespace MoudelMain.ViewModels
{
    public class MainViewModel
    {
        public DelegateCommand OpenPage { get; set; }

        private readonly IRegionManager regionManager;


        //构造函数中注入IRegionManager类实现区域管理。
        //Regions["ContentRegion"]找到视图中定义的区域。
        //RequestNavigate("PageA")实现页面导航跳转展示
        public MainViewModel(IRegionManager regionManager)
        {
            OpenPage = new DelegateCommand(Open);

            this.regionManager = regionManager;
        }

        private void Open(string obj)
        {
            regionManager.Regions["ContentRegion"].RequestNavigate(obj);
        }
    }
}

效果展示:

二十五、Prism框架_第10张图片


 6、扩展:依赖注入DI,控制反转Ioc

你可能感兴趣的:(c#,asp.net,wpf)