1.Prism框架介绍

1.Prism框架介绍 .Prism Prism 框架介绍

什么是Prism

1.WPF Prism是一个用于构建模块化、可扩展和可重用的WPF应用程序的框架。它基于MVVM模式,提供了一种简单且灵活的方式来管理复杂的WPF应用程序。

2.Prism框架提供了一些核心概念,包括模块化开发、依赖注入、命令模式、导航和事件聚合等。它还提供了一些实用工具和类来简化开发过程,例如模块加载器、事件聚合器、导航器等。

3.Prism框架的主要目标是帮助开发人员构建易于维护和扩展的WPF应用程序,同时提高代码的可重用性和可测试性。

Github:https://github.com/PrismLibrary/Prism

Prism包括哪些功能模块

      1.Region(区域管理)
      2.Module(模块)
      3.View Injection(视图注入)
      4.ViewModelLocationProvider(视图模型定位)
      5.Command(绑定相关)
      6.Event Aggregator (事件聚合器)
      7.Navigation(导航)
      8.Dialog(对话框)

功能↓ / →框架名 Prism Mvvmlight Micorosoft.Toolkit.Mvvm 通知 BindableBase ViewModelBase ObservableObject 命令 DelegateCommand RelayCommand Async/RelayCommand 聚合器 IEventAggregator IMessenger IMessenger 模块化 √ × × 容器 √ × × 依赖注入 √ × × 导航 √ × × 对话 √ × ×

 

创建Prism应用程序:

第一步:创建WPF应用程序(我这里用NET6.0)

第二步:引用Prism.Unity框架

第三部:修改App.xaml文件

<prism:PrismApplication x:Class="WpfApp_test.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Shell"
             xmlns:prism="http://prismlibrary.com/">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
               
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</prism:PrismApplication>
 public partial class App : PrismApplication
    {
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
             
        }

        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }
}

View和ViewModel实现绑定

添加Views和ViewModels文件夹,在Views文件夹里添加MainWindow.xaml和在ViewModels添加MainWindowViewModel.cs 

<Window x:Class="WpfApp_test.Views.MainWindow"
        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:WpfApp_test.Views"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"    
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
    </Grid>
</Window>

或者在App.cs中进行注册

 protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<MainWindow, MainWindowViewModel>();
        }

亦或者在MainWindow.xaml.cs

this.DataContext = new MainWindowViewModel();

 

View和ViewModel数据绑定

<Window x:Class="WpfApp1.Views.MainWindow"
        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.Views"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="{Binding Title}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20"/>
            <Button Content="确定" Command="{Binding TitleCommand}" Height="30" Width="50"/>
            <Button  FontSize="30"  Content="带参数" Margin="10" Height="60" Command="{Binding GetParameterCommand}"  CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"/>
            <Button x:Name="button" FontSize="30"  Content="behaviors带参数" Margin="10" Height="60" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <i:InvokeCommandAction Command="{Binding BehaviorsClickCommand}" CommandParameter="{Binding ElementName=button}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
       
    </Grid>
</Window>
 public class MainWindowViewModel: BindableBase
    {
        private string _title;
        public string Title
        {
            get { return _title; }
            set { _title = value; RaisePropertyChanged(); }
        }

        public DelegateCommand TitleCommand { get; private set; }
        public DelegateCommand<Button> GetParameterCommand { get; private set; }
        public DelegateCommand<Button> BehaviorsClickCommand { get; private set; }

        public MainWindowViewModel()
        {
            TitleCommand = new DelegateCommand(TitleAction);
            GetParameterCommand = new DelegateCommand<Button>(GetParameterAction);
            BehaviorsClickCommand = new DelegateCommand<Button>(BehaviorsClickAction);
        }

        private void TitleAction()
        {
            Title = "Prism应用程序!";
        }
        private void GetParameterAction(Button obj)
        {
            obj.Content = "GetParameter";
        }
        private void BehaviorsClickAction(Button obj)
        {
            obj.Content = "BehaviorsClick";
        }
    }

 

区域(Region)

页面显示的区域划分称N个Region, 此时, 每个Region将变成了动态分配区域。它将负责承担我们的UI组件或者控件。

 

区域定义

添加一个用户控件页面Content.xaml

在MainWindow页面添加

 <ContentControl x:Name="Content" />
 <Grid Grid.Row="1">
            <!--<ContentControl  prism:RegionManager.RegionName="{x:Static share:RegionNames.MainRegion}"/>-->
            <ContentControl x:Name="Content" />
        </Grid>

 

在MainWindow.xaml.cs

public partial class MainWindow : Window
    {
        public MainWindow(IRegionManager regionManager)
        {
            InitializeComponent();
            //为界面元素注册区域
            RegionManager.SetRegionName(Content, "ContentRegion");
            //为指定区域指定页面
            regionManager.RegisterViewWithRegion("ContentRegion", typeof(Content));

        }
}

在Prism中, 控件都支持注册Region, 只是有些控件需要自己实现一个RegionAdapters(区域适配器),Prism提供了许多内置得RegionAdapter。
如:ContentControlRegionAdapter ,ItemsControlRegionAdapter ,SelectorRegionAdapter等。

 

 模块(Module)

对于微服务的思想来说,对于特定功能服务都可以独立存在,在WPF中那么意味着, 每个独立的功能我们都可以称之为模块。

模块添加操作流程:

1.添加一个新的项目,WPF用户控件项目。

2.添加引用,Prism.Unity框架。

3.添加一个类。并继承于IModule,实现OnInitialized和RegisterTypes方法

4.添加两个文件夹Views和ViewModels

5.项目-->属性-->生成-->事件--生成后事件

xcopy "$(ProjectDir)\bin\Debug\net6.0-windows\$(ProjectName).dll" "$(SolutionDir)\WPFClient\bin\Debug\net6.0-windows\Modules\" /Y /S
xcopy "$(ProjectDir)\bin\Release\net6.0-windows\$(ProjectName).dll" "$(SolutionDir)\WPFClient\bin\Release\net6.0-windows\Modules\" /Y /S

这个是生成该项目后,dll之间复制到主项目的bin目录下去。

6.在主项目WPFClient的bin目录下添加一个文件夹Modules。

7.在主项目的APP类文件里重写CreateModuleCatalog方法

protected override IModuleCatalog CreateModuleCatalog()
        {
            return new DirectoryModuleCatalog()
            {
                ModulePath = AppContext.BaseDirectory + $"\\Modules" //获取WPFModule.dll的目录
            };
        }

还有一种是通过引用项目的方法来添加

        /// <summary>
        /// 通过引用来获取其它模块的页面
        /// </summary>
        /// <param name="moduleCatalog"></param>
        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            base.ConfigureModuleCatalog(moduleCatalog);
            moduleCatalog.AddModule<WPF.Common.CommonProfile>();//模块的IModule类
        }

 

8.生成解决方法。

 

IRegionManager

怎样把子模块的页面呈现到主项目的ContentControl 区域中呢?

案列:

public class ImageModuleProfile : IModule
    {
        private readonly IRegionManager _regionManager;

        public ImageModuleProfile(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }


        public void OnInitialized(IContainerProvider containerProvider)
        {
//ImageView是子项目的页面, ContentControlName.MainmoduleImagemoduleReginName是区域的名称 _regionManager.RegisterViewWithRegion
<ImageView>(ContentControlName.MainmoduleImagemoduleReginName); } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ImageView, ImageViewModel>(); } }

或者

_regionManager.RegisterViewWithRegion(ContentControlName.MainmoduleImagemoduleReginName, typeof(ImageView));

 

聚合器IEventAggregator

//创建事件
public class SavedEvent : PubSubEvent<string> { }

//发布
IEventAggregator.GetEvent<SavedEvent>().Publish("some value");

//订阅
IEventAggregator.GetEvent<SavedEvent>().Subscribe(.Subscribe(message=>
            {
                //do something
            });

 

Navigation导航功能

案例:

IRegionManager regionManager = …;//构造函数中获取
regionManager.RequestNavigate("RegionName", "ViewName");//跳转页面

带参数的跳转

var param = new NavigationParameters();
param.Add("Parameter", param);
_regionManger.RequestNavigate("RegionName", "ViewName", param);

//类似URL地址传递参数
_regionManger.RequestNavigate("RegionName", "ViewName?id=1&Name=xiaoming");

INavigationAware

VM类继承该接口要实现3个方法

 public void OnNavigatedTo(NavigationContext navigationContext)
        {

        }

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }

OnNavigatedTo: 导航完成前, 此处可以传递过来的参数以及是否允许导航等动作的控制。
IsNavigationTarget: 调用以确定此实例是否可以处理导航请求。否则新建实例
OnNavigatedFrom: 当导航离开当前页时, 类似打开A, 再打开B时, 该方法被触发。

接受跳转过来带的参数

public void OnNavigatedTo(NavigationContext navigationContext)
        {
            var id = navigationContext.Parameters.GetValue<int>("id");

            var name = navigationContext.Parameters["Name"].ToString();
        }

 

INavigationAware

该接口继承于INavigationAware, 所以, 它多了一个功能: 允许用户针对导航请求进行拦截。

//多了一个回调函数, 该值觉得是否拦截该导航请求
    void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback);

当打开新的导航时, 或许有些情况下你需要经过用户进行确认, 这个时候, IConfirmNavigationRequest接口可以满足需求, 如下:

public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            bool result = true;

            if (MessageBox.Show("确认导航?", "温馨提示", MessageBoxButton.YesNo) == MessageBoxResult.No)
                result = false;

            //通过回调当前返回的确认结果,决定是否启动该导航
            continuationCallback(result);
        }

Navigation Journal
导航日志, 其实就是对导航系统的一个管理功能, 理论上来说, 我们应该知道我们上一步导航的位置、以及下一步导航的位置, 包括我们导航的历史记录。以便于我们使用导航对应用程序可以灵活的控制。

IRegionNavigationJournal
该接口包含以下功能:

GoBack() : 返回上一页
CanGoBack : 是否可以返回上一页
GoForward(): 返回后一页
CanGoForward : 是否可以返回后一页

 

IDialogAware对话框

public interface IDialogAware
{
string Title { get; }
event Action<IDialogResult> RequestClose;
bool CanCloseDialog();
void OnDialogClosed();
void OnDialogOpened(IDialogParameters parameters);
}

注册对话框 RegisterDialog

protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //仅注册视图
            containerRegistry.RegisterDialog<MessageDialog>();

            //注册视图时绑定VM
            containerRegistry.RegisterDialog<MessageDialog, MessageDialogViewModel>();

            //添加别名
            containerRegistry.RegisterDialog<MessageDialog>("DialogName");
        }

使用IDialogService接口 Show/ShowDialog 方法调用对话框

private readonly IDialogService dialogService;

        private void ShowDialog()
        {
            DialogParameters keys = new DialogParameters();
            keys.Add("message", "Hello,Prism!");

            dialogService.ShowDialog("MessageDialog", keys, arg =>
            {
                
            });
        }

 

评论