WPF Prism框架应用

1,介绍。

1.1,什么是Prism?

微软MVVM模式的开源框架。

Prism是由Microsoft社区维护的超轻量级开源框架,其前身为Angel项目。该框架采用模块化架构设计,支持MVVM模式、依赖注入和事件聚合机制,可应用于WPF、Xamarin.Forms、UWP等多个开发平台 。截止2025年5月,Prism已形成包含核心库、平台专用模块的完整技术生态。

1.2,架构

模块化架构

  • 支持将应用拆分为独立功能模块,通过IModule接口实现动态加载
  • 提供Region区域容器管理系统,实现视图动态组合与界面元素灵活布局
  • 支持配置文件、代码声明、目录扫描三种模块加载方式
1.3,实现

依赖注入实现

  • 内置IoC容器可管理组件依赖关系,支持Unity/Autofac等多种容器扩展
  • ViewModelLocator自动绑定视图与视图模型,通过容器解析依赖实例
  • 在WPF项目中使用Bootstrapper初始化容器配置,实现服务注册与组件装配
1.4,导航与通信机制
  • FrameNavigationService提供结构化导航服务,支持参数传递与视图生命周期管理
  • 事件聚合器(PubSubEvents)实现模块间松耦合通信,支持跨线程消息分发
  • DelegateCommand改进异步操作支持,分离UI操作触发与业务逻辑执行
1.5, 跨平台支持
  • 2014年发布的Prism 5.0将核心功能拆分为四个独立程序集,支持.NET 4.5/WPF平台按需加载
  • 提供可移植类库(PCL)实现视图模型在WPF/[Windows Phone](https://baike.baidu.com/item/Windows Phone/9227600?fromModule=lemma_inlink)/[Windows Store](https://baike.baidu.com/item/Windows Store/9970749?fromModule=lemma_inlink)平台复用
  • Windows Runtime\](https://baike.baidu.com/item/Windows Runtime/1676385?fromModule=lemma_inlink)版本集成会话状态管理、输入验证等特性,适配Windows 8.x/Phone 8.x应用开发

Unity与DryIoc是Prism框架中两种不同的依赖注入容器,它们在功能、使用场景和性能上存在显著差异。以下是两者的主要区别:

1‌. 功能支持

  • Unity ‌:功能更全面,支持在OnStartup方法中进行服务注册和实例获取‌。此外,Prism.Unity.Extensions需要较新版本(基础环境需4.6.1)。
  • DryIoc ‌:功能相对精简,无法在OnStartup方法中直接注册或获取实例‌。其关联的DLL更少,文件占用更小‌。

2‌. 多模块支持

  • 在多模块项目中,‌Unity ‌通过PrismContainerExtension.Current确保所有模块使用同一容器实例,更适合保证唯一性(如与SQLSugar配合时)‌。
  • DryIoc ‌在多模块场景下可能需依赖ContainerLocator.Current,实例一致性较弱‌。

3‌. 版本与兼容性

  • Unity ‌:推荐使用8.0及以上版本,因ContainerLocator.Current的引入更完善‌。

  • DryIoc‌:作为Prism 8.0后仅保留的两种容器之一,其集成更轻量,但功能扩展性有限‌。

    1. 适用场景
  • Unity‌:适合需要复杂依赖注入、多模块协同或动态服务注册的场景‌。

  • DryIoc‌:适合追求轻量化、快速启动且对容器功能要求不高的项目‌。

总结

选择时需权衡功能需求与项目规模:若需模块化、动态注册或强一致性,优先选‌Unity ‌;若注重轻量化和简洁性,‌DryIoc‌更合适‌。

2,准备

这里以prism.DryIoc容器为例。

2.1,添加Prism.DryIoc
2.2,修改入口文件app.xaml
xaml 复制代码
<prism:PrismApplication x:Class="PrismBaseObj.App"
             xmlns:prism="http://prismlibrary.com/"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PrismBaseObj"
             > 
</prism:PrismApplication>
C# 复制代码
 public partial class App : PrismApplication
    {      
    }

3,视图与视图模型的绑定

3.1,设置启动窗口。
C# 复制代码
 public partial class App : PrismApplication
 {
        protected override Window CreateShell()
        {
            //设置MainWindow为启动窗口
            return Container.Resolve<MainWindow>();
        }
 }
3.2,关联View(视图)到ViewModel(视图模型)
  • 设置附加属性prism:ViewModelLocator.AutoWireViewModel="True"使视图自动定位到对应的视图模型
xaml 复制代码
<Window x:Class="PrismBaseObj.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:PrismBaseObj"
        xmlns:prism="http://prismlibrary.com/"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" prism:ViewModelLocator.AutoWireViewModel="True">
  • 默认情况下,ViewViewModel的类名存在以下对应关系。

    • 情况1:位于Views文件中视图类名为:A(即View类全名包含了Views),自动关联到ViewModels文件夹中(即类全名包含了ViewModels)的类名为A+ViewModel的类,特别需要注意的是:默认情况下查找匹配的是从第一个View开始,所以如果A+ViewModel=*ViewViewModel查找到的是ViewView将出现未找到ViewModel的异常。

      C# 复制代码
      namespace PrismBaseObj.ViewModels
      {
          class LoginViewModel
          {
              public string UserName { get; set; } = "admin";
          }
      }
      namespace PrismBaseObj.Views
      {
          /// <summary>
          /// LoginView.xaml 的交互逻辑
          /// </summary>
          public partial class LoginView : Window
          {
              public LoginView()
              {
                  InitializeComponent();
              }
          }
    • 情况2,视图类B命名空间不包含Views时,则关联到同一命名空间下类名为B+ViewModel类,例如:PrismBaseObj.MainWindow对应PrismBase.MainWindowViewModel

      C# 复制代码
      //命名空间不包含Views
      namespace PrismBaseObj
      {
          /// <summary>
          /// MainWindow.xaml 的交互逻辑
          /// </summary>
          public partial class MainWindow : Window
          {
              public MainWindow()
              {
                  InitializeComponent();
              }
          }
      }
      //命名空间不包含ViewModels
      namespace PrismBaseObj
      {
          class MainWindowViewModel : BindableBase
          {
          }
      }
    • 情况3,视图类名以View结束时,对应的视图模型为该是视图类名+Model

  • 自定义视图与视图模型的绑定规则。

    C# 复制代码
    public partial class App : PrismApplication
        {
            protected override Window CreateShell()
            {
                //设置启动窗口
                return Container.Resolve<Views.LoginView>();
            }
            protected override void ConfigureViewModelLocator()
            {
                // base.ConfigureViewModelLocator();
    
                //自定义视图与视图模型的绑定规则。
                ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewtype =>
                {
                    //指定视图模型类型为:视图名+ViewModel
                    string typeName = viewtype.FullName + "ViewModel";
                    Type t = Type.GetType(typeName);
                    return t;
                });
                //直接建立绑定关系
                //ViewModelLocationProvider.Register("MainWindow", typeof(MainWindowViewModel));
            }
    }

4,弹窗。

弹窗包含两部分:一部分是弹窗内容,另外部分是弹窗窗口。

4.1,弹窗内容(视图模型需要实现IDialogAware)。
4.1.1,注册弹窗内容。

弹窗内容一般是UserControl或者是Page,不能是窗体,因为弹窗对象会添加一个窗体作为宿主。

C# 复制代码
  public partial class App : PrismApplication
    {       
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {          
           //注册弹窗
            //注册对象只能是page或者是控件不能是窗体,因为其会添添加一个驻在容器窗体
            containerRegistry.RegisterDialog<Dialog.SampleDialog>();
         
        }    
    }
4.1.2,调用弹窗。
xaml 复制代码
<UserControl x:Class="PrismBaseObj.Dialog.SampleDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PrismBaseObj.Dialog"
             mc:Ignorable="d" 
             xmlns:prims="http://prismlibrary.com/"
             d:DesignHeight="450" d:DesignWidth="800" prims:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
        <TextBlock Text="示例弹窗"></TextBlock>   
    </Grid>
</UserControl>

弹窗的视图模型:

C# 复制代码
namespace PrismBaseObj.Dialog
{
    /// <summary>
    /// 弹窗的视图模型,需要继承实现IDialogAware
    /// </summary>
    class SampleDialogViewModel : Prism.Services.Dialogs.IDialogAware
    {
        public string Title => "示例窗体";

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog()
        {
            //是否可以关闭窗体
            return true;
        }

        public void OnDialogClosed()
        {
            //窗体关闭后发生
        }

        public void OnDialogOpened(IDialogParameters parameters)
        {
            
        }
    }
}
xaml 复制代码
<Window x:Class="PrismBaseObj.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:PrismBaseObj"
        xmlns:prism="http://prismlibrary.com/"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid>
       
        <Button Content="打开对话框" Command="{Binding OpenDialogCommand}"></Button>
    </Grid>
</Window>
C# 复制代码
namespace PrismBaseObj
{
    class MainWindowViewModel : BindableBase
    {
        //在构造函数中提供服务
        public MainWindowViewModel(Prism.Services.Dialogs.IDialogService dialogService)
        {           
            ModifyCommand = new DelegateCommand(DoModifyCammand, CanDomodifyCammand);
            OpenDialogCommand = new DelegateCommand(()=>
            {
                dialogService.Show("SampleDialog", null, a=> {
                    var t = a.Parameters;
                });
            });
        }                
        public Prism.Commands.DelegateCommand OpenDialogCommand { get; set; }

    }

注意事项

如果启动运行时提示以下异常:

**原因:**前文重写了用于配置视图与视图模型绑定规则的方法ConfigureViewModelLocator()导致。如下:

C# 复制代码
public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            //设置启动窗口
            return Container.Resolve<Views.LoginView>();
        }
        protected override void ConfigureViewModelLocator()
        {
            // base.ConfigureViewModelLocator();
            //自定义视图与视图模型的绑定规则。
            ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewtype =>
            {
                //指定视图模型类型为:视图名+ViewModel
                string typeName = viewtype.FullName + "ViewModel";
                Type t = Type.GetType(typeName);
                return t;
            });
            //直接建立绑定关系
            //ViewModelLocationProvider.Register("MainWindow", typeof(MainWindowViewModel));
        }
}

处理办法:

方法1:默认绑定规则,不自定义绑定规则。

方法2:进行如下变更。

C# 复制代码
 protected override void ConfigureViewModelLocator()
        {
            // base.ConfigureViewModelLocator();
            //配置视图模型的定位规则,即视图与哪个视图模型绑定
            ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver(viewtype =>
            {
                //指定视图模型类型为:视图名+ViewModel
                string typeName = viewtype.FullName + "ViewModel";
                Type t = Type.GetType(typeName);
                return t;
            });
            //告诉ViewModelProvidence用容器创建ViewModel(避免 Activator.CreateInstance 调用无参构造函数)
            ViewModelLocationProvider.SetDefaultViewModelFactory((view,viewmodelType)=> {
                return Container.Resolve(viewmodelType);
            });
            //直接建立绑定关系
            //ViewModelLocationProvider.Register("MainWindow", typeof(MainWindowViewModel));
        }
4.1.3,关闭弹窗。
  • 通过窗体的关闭按钮关闭。

  • 自定义关闭按钮,关闭。

    xaml 复制代码
    <Grid>
            <TextBlock Text="Dialog弹窗" FontSize="20" Foreground="Orange" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
            <Button HorizontalAlignment="Right" VerticalAlignment="Top" Width="80" Height="80" Content="关闭" Command="{Binding CloseCommand}"></Button>
        </Grid>
    C# 复制代码
    public interface IDialogAware
        {
            //
            // 摘要:
            //     The title of the dialog that will show in the Window title bar.
            string Title { get; }
    
            //
            // 摘要:
            //     Instructs the IDialogWindow to close the dialog.
            event Action<IDialogResult> RequestClose;
    
            //
            // 摘要:
            //     Determines if the dialog can be closed.
            //
            // 返回结果:
            //     True: close the dialog; False: the dialog will not close
            bool CanCloseDialog();
            //
            // 摘要:
            //     Called when the dialog is closed.
            void OnDialogClosed();
            //
            // 摘要:
            //     Called when the dialog is opened.
            //
            // 参数:
            //   parameters:
            //     The parameters passed to the dialog
            void OnDialogOpened(IDialogParameters parameters);
        }
     class SampleDialogViewModel : Prism.Services.Dialogs.IDialogAware
        {
            public string Title => "SampleDialog示例";
    //实现接口定义的事件
            public event Action<IDialogResult> RequestClose;
            public SampleDialogViewModel()
            {
                CloseCommand = new Prism.Commands.DelegateCommand(() => {
                    Prism.Services.Dialogs.DialogResult dialogResult = new DialogResult();
                    dialogResult.Parameters.Add("LogInOk?", true);
                    //调用该委托即可实现窗口的关闭
                    //IDialogService的
                    //void Show(string name, IDialogParameters parameters, Action<IDialogResult> callback);
                    //回调方法callback添加在RequestClose上
                    RequestClose?.Invoke(dialogResult);
                });
            }
            public bool CanCloseDialog()
            {
                return true;
            }
    
            public void OnDialogClosed()
            {
                
            }
    
            public void OnDialogOpened(IDialogParameters parameters)
            {
                
            }
           public Prism.Commands.DelegateCommand CloseCommand { get; set; }
        }
4.2,弹窗窗体。
4.2.1,自定义默认弹窗窗体样式
xaml 复制代码
<UserControl x:Class="PrismBaseObj.Dialog.SampleDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PrismBaseObj.Dialog"
             mc:Ignorable="d" 
             xmlns:prims="http://prismlibrary.com/"
             d:DesignHeight="450" d:DesignWidth="800" prims:ViewModelLocator.AutoWireViewModel="True" >
    <prims:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="Width" Value="400"></Setter>
            <Setter Property="Height" Value="300"></Setter>
            <Setter Property="WindowChrome.WindowChrome">
                <Setter.Value>
                    <WindowChrome GlassFrameThickness="-1" UseAeroCaptionButtons="False"></WindowChrome>
                </Setter.Value>
            </Setter>
        </Style>
    </prims:Dialog.WindowStyle>
    <Grid>
       
        <TextBlock Text="示例弹窗"></TextBlock>   
    </Grid>
</UserControl>
4.2.2,注册自定义弹窗窗体。

弹窗对象都有一个宿主窗口,而这个窗口都实现了接口:IDialogWindow

  • 定义弹窗对象的宿主窗口。

    xaml 复制代码
    <Window x:Class="PrismBaseObj.HostForm.BorderlessForm"
            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:PrismBaseObj.HostForm"
            mc:Ignorable="d"
            Title="{Binding Title}" Height="450" Width="800" WindowStyle="ThreeDBorderWindow">
      
    </Window>

    窗口实现接口:IWindowDialog

    c# 复制代码
     public partial class BorderlessForm : Window,Prism.Services.Dialogs.IDialogWindow
        {
            public BorderlessForm()
            {
                InitializeComponent();
            }
    
            public IDialogResult Result { get ; set ; }
        }
  • 注册弹窗窗体。

    复制代码
    public partial class App : PrismApplication
        {
            
            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {          
               //注册弹窗
                //注册对象只能是page或者是控件不能是窗体,因为其会添添加一个驻在容器窗体
                containerRegistry.RegisterDialog<Dialog.SampleDialog>();
                //注册弹窗的窗体
                containerRegistry.RegisterDialogWindow<HostForm.BorderlessForm>();
            }
    }
  • 弹出弹窗时将自动适用注册弹窗窗体,需要注意的是,其样式优先级低于prims:Dialog.WindowStyle

5,命令

xaml 复制代码
<Window x:Class="Command应用.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:Command应用"
        mc:Ignorable="d"
        xmlns:prism="http://prismlibrary.com/"
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        Title="{Binding Title}" Height="450" Width="800" prism:ViewModelLocator.AutoWireViewModel="True">
    <Grid Background="Transparent">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <!--<i:InvokeCommandAction Command="{Binding ButtonCommand}"  ></i:InvokeCommandAction>-->
                <prism:InvokeCommandAction Command="{Binding ButtonCommand}" ></prism:InvokeCommandAction>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>
C# 复制代码
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Command应用
{
    class MainWindowViewModel:BindableBase
    {
        public MainWindowViewModel()
        {
            ButtonCommand = new Prism.Commands.DelegateCommand<object>(obj =>
              {
                  //当为:<prism:InvokeCommandAction Command="{Binding ButtonCommand}"></prism:InvokeCommandAction>
                  //obj为:System.Windows.Input.MouseButtonEventArgs
                  //xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                  //当为:<i:InvokeCommandAction Command="{Binding ButtonCommand}" ></i:InvokeCommandAction>
                  //obj为:null
              });
        }
        public Prism.Commands.DelegateCommand<object> ButtonCommand { get; set; }
        private string title="示例";
        public string Title
        {
            get { return title; }
            set { SetProperty<string>(ref title, value); }
        }
    }
}

6,事件总线-消息

  • 定义事件,该事件需要继承自EventBase,但EventBase类没有定义Subscribe(),定义了Subscribe()方法的是其派生类PubSubEvent,所以这里继承PubSubEvent

    C# 复制代码
     //无参
        class EventMessage:Prism.Events.PubSubEvent
        {
        }
        //带参
        class EventMessageArgs : Prism.Events.PubSubEvent<object>
        {
    
        }
  • 注入,消息订阅或者发布。

    C# 复制代码
     class MainWindowViewModel:Prism.Mvvm.BindableBase
        {
            public MainWindowViewModel(Prism.Events.IEventAggregator eventAggregator)
            {
                // 1,获取消息对象,通过注入的方式获取。
                // 2,通过事件对象进行订阅或者发布
                // 3,eventAggregator:单例模式
                // 总线  事件对象
                eventAggregator.GetEvent<EventMessage>().Subscribe(Receive);
                //有参
                eventAggregator.GetEvent<EventMessageArgs>().Subscribe(Receive2);
            }
        
            //无参
            private void Receive()
            {
                
            }
            //有参
            private void Receive2(object obj)
            {
    
            }
        }
  • 事件总线的过滤。

    C# 复制代码
     //keepSubscriberReferenceAlive:
    // 默认为false,表示弱引用。
    // true:表示强引用,意味着对象销毁时,需要进行UnSubcribe(取消订阅销毁操作)
    
    //ThreadOption :
    //默认值 :PublisherThread:发布者在什么线程发布,订阅的方法就在哪个线程执行。
    //UIThread:不管发布者在哪个线程发布,订阅的方法始终在UI线程执行。
    //BackgroundThread:不管发布者在哪个线程发布,订阅的方法始终在BackgroundThread执行。
    
    //Predicate<TPayload> filter:过滤条件
    public virtual SubscriptionToken Subscribe(Action<TPayload> action, ThreadOption threadOption, bool keepSubscriberReferenceAlive, Predicate<TPayload> filter);

7,区域化Region

7.1,Prism提供的默认适配器
  • ContentControlRegionAdapter
    • 适用于:ContentControl
  • ItemsControlRegionAdapter
    • 适用于:ItemsControl
  • SelectorRegionRegionAdapter
    • 适用于:ListBox,ListView
  • TabControlRegionAdapter
    • 使用与:TabControl

示例:

xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Base.Views.ViewA"
        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:lzg.PrismRegion.Base.Views"
        mc:Ignorable="d"
         
          d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="ForestGreen">
        <TextBlock FontSize="30" Text="ViewA" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
    </Grid>
</UserControl>
xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Base.Views.ViewB"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:lzg.PrismRegion.Base.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="SkyBlue">
        <TextBlock FontSize="30" Text="ViewB" Foreground="Blue" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
    </Grid>
</UserControl>

在Region中注册视图

c# 复制代码
namespace lzg.PrismRegion.Base.Views
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow(Prism.Regions.IRegionManager regionManager)
        {
            InitializeComponent();
            //一个区域里可以包含多个视图
            regionManager.RegisterViewWithRegion("RegionView", typeof(ViewA));
            regionManager.RegisterViewWithRegion("RegionView", typeof(ViewB));
            this.Loaded += (obj, e) =>
            {
                //设置激活的View
                var view = regionManager.Regions["RegionView"].Views.FirstOrDefault(item => item.GetType().Name.Equals("ViewB"));
                regionManager.Regions["RegionView"].Activate(view);
            };
           
        }
    }
}

在UI中使用Region

  • 使用ContentControl显示单个View
xaml 复制代码
<Window x:Class="lzg.PrismRegion.Base.Views.MainWindow"
        xmlns:prism="http://prismlibrary.com/"
        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:lzg.PrismRegion.Base.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <Grid DockPanel.Dock="Top" Height="40" >
            <TextBlock Text="Header" FontSize="20"></TextBlock>
        </Grid>
        <StackPanel DockPanel.Dock="Left" Width="80">
            <Button Content="ViewA"></Button>
            <Button Content="ViewB"></Button>
            <Button Content="ViewC"></Button>
        </StackPanel>
        <Grid>
            <!--使用Region-->
            <ContentControl prism:RegionManager.RegionName="RegionView"></ContentControl>
        </Grid>
    </DockPanel>
</Window>

显示效果:

  • 使用ItemsControl显示多个视图

    xaml 复制代码
    <Window x:Class="lzg.PrismRegion.Base.Views.MainWindow"
            xmlns:prism="http://prismlibrary.com/"
            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:lzg.PrismRegion.Base.Views"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <DockPanel>
            <Grid DockPanel.Dock="Top" Height="40" >
                <TextBlock Text="Header" FontSize="20"></TextBlock>
            </Grid>
            <StackPanel DockPanel.Dock="Left" Width="80">
                <Button Content="ViewA"></Button>
                <Button Content="ViewB"></Button>
                <Button Content="ViewC"></Button>
            </StackPanel>
            <Grid>
                <!--使用Region-->
                <!--单个显示-->
                <!--<ContentControl prism:RegionManager.RegionName="RegionView"></ContentControl>-->
                <!--多个显示-->
                <ItemsControl prism:RegionManager.RegionName="RegionView"></ItemsControl>
            </Grid>
        </DockPanel>
    </Window>
7.2,自定义区域适配器
  • 自定义适配器

    C# 复制代码
     class UniformRegionAdapter : Prism.Regions.RegionAdapterBase<UniformGrid>
        {
            public UniformRegionAdapter(Prism.Regions.IRegionBehaviorFactory factory) : base(factory)
            {
    
            }
            protected override void Adapt(IRegion region, UniformGrid regionTarget)
            {
    
                region.Views.CollectionChanged += (ea, eg) =>
                {
                    if (eg.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                    {
                        foreach (var item in eg.NewItems)
                        {
                            UIElement element = item as UIElement;
                            regionTarget.Children.Add(element);
                        }
    
                    }
                    if (eg.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
                    {
                        foreach (var item in eg.NewItems)
                        {
                            UIElement element = item as UIElement;
                            regionTarget.Children.Remove(element);
                        }
                    }
                };
            }
    
            protected override IRegion CreateRegion()
            {
                return new Prism.Regions.Region();
            }
        }
  • 注册自定义的适配器

    C# 复制代码
     /// <summary>
        /// App.xaml 的交互逻辑
        /// </summary>
        public partial class App : Prism.DryIoc.PrismApplication
        {
            protected override Window CreateShell()
            {
                return Container.Resolve<Views.MainWindow>();
            }
            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {
               
            }
            protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
            {
                base.ConfigureRegionAdapterMappings(regionAdapterMappings);
                //注册自定义适配器
                regionAdapterMappings.RegisterMapping<System.Windows.Controls.Primitives.UniformGrid, UniformRegionAdapter>();
            }
        }
  • 应用

    xaml 复制代码
    <Window x:Class="lzg.PrismRegion.Base.Views.MainWindow"
            xmlns:prism="http://prismlibrary.com/"
            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:lzg.PrismRegion.Base.Views"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <DockPanel>
            <Grid DockPanel.Dock="Top" Height="40" >
                <TextBlock Text="Header" FontSize="20"></TextBlock>
            </Grid>
            <StackPanel DockPanel.Dock="Left" Width="80">
                <Button Content="ViewA"></Button>
                <Button Content="ViewB"></Button>
                <Button Content="ViewC"></Button>
            </StackPanel>
            <Grid>
                <!--使用Region-->
                <!--单个显示-->
                <!--<ContentControl prism:RegionManager.RegionName="RegionView"></ContentControl>-->
                <!--多个显示-->
                <!--<ItemsControl prism:RegionManager.RegionName="RegionView"></ItemsControl>-->
               <!--使用自定义的适配器--!>
                <UniformGrid Columns="3" Rows="2" prism:RegionManager.RegionName="RegionView"></UniformGrid>
            </Grid>
        </DockPanel>
    </Window>
7.3,页面导航-参数传递
7.3.1,导航页面注册
xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Navigation.Views.Pages.ViewA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:lzg.PrismRegion.Navigation.Views.Pages"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="GreenYellow">
        <TextBlock FontSize="20" Text="ViewA" Foreground="Black"></TextBlock>
    </Grid>
</UserControl>
xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Navigation.Views.Pages.ViewB"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:lzg.PrismRegion.Navigation.Views.Pages"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="Pink">
        <TextBlock Text="ViewB" FontSize="20"></TextBlock>
    </Grid>
</UserControl>
C# 复制代码
  public partial class App : PrismApplication
    {
        
        protected override Window CreateShell()
        {
           return Container.Resolve<Views.MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //注册导航视图视图,注意视图是控件不是窗体
            containerRegistry.RegisterForNavigation(typeof(Views.Pages.ViewA), "ViewA");
            containerRegistry.RegisterForNavigation<Views.Pages.ViewB>("ViewB");
        }
    }
7.3.2,定义支持参数的视图模型

若需要支持参数传递,则页面视图模型需要实现INavigationAware接口

c# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Prism.Regions;
namespace lzg.PrismRegion.Navigation.ViewModels.Pages
{
    class ViewAViewModel : INavigationAware
    {
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewA");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
           string addr= navigationContext.Parameters.GetValue<string>("Addr");
            navigationContext.Parameters.Add("Addr3", "ViewA");
        }
    }
}
C# 复制代码
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lzg.PrismRegion.Navigation.ViewModels.Pages
{
    class ViewBViewModel : INavigationAware
    {
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            //true:表示实例接收导航请求,即多次导航也只有一个实例
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewB");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            //接收来自 RequestNavigate(string regionName, string target, NavigationParameters navigationParameters);
            //的navigationParameters,也可以接收来自上一个视图的OnNavigatedFrom(NavigationContext navigationContext)
            //如果两个同时传参而key值相同则以 RequestNavigate为准
            string addr = navigationContext.Parameters.GetValue<string>("Addr");
        }
    }
}
7.3.3,导航到视图
C# 复制代码
 class MainWindowViewModel
    {
        public string Description { get; set; } = "视图导航案例";
        public MainWindowViewModel(Prism.Regions.IRegionManager regionManager)
        {
            OpenCommand = new Prism.Commands.DelegateCommand<string>(viewName =>
              {
                  //视图导航
                  //方法1,缺点:不能给视图传递参数,重复添加视图
                  // regionManager.RegisterViewWithRegion("RegionView", viewName);
                  // object obj = regionManager.Regions["RegionView"].Views.LastOrDefault(view => view.GetType().Name.Equals(viewName, StringComparison.InvariantCultureIgnoreCase));
                  // regionManager.Regions["RegionView"].Activate(obj);
                  //方法2,可以传递参数,可选择是否重复添加视图。缺点:ViewModel需要实现接口INavigationAware
                  //if (viewName == "ViewA")
                  //{
                      Prism.Regions.NavigationParameters paras = new Prism.Regions.NavigationParameters();
                      paras.Add("Addr", "来自于ManiWindow");
                      regionManager.RequestNavigate("RegionView", viewName, paras);
                  //}
                  //else
                  //{
                  //    regionManager.RequestNavigate("RegionView", viewName);
                  //}
                 
              });
        }
        public Prism.Commands.DelegateCommand<string> OpenCommand { get; set; }
    }

效果:

7.4,导航页面生命周期

页面视图模型实现接口IRegionMemberLifetTime对区域内的视图生命周期进行管理。该接口只有定义一个属性KeepAlive

KeepAlive:

  • true表示是失活时保留该视图实例
  • false表示视图非激活状态时销毁该实例。
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Prism.Regions;
namespace lzg.PrismRegion.Navigation.ViewModels.Pages
{
    class ViewAViewModel : INavigationAware,IRegionMemberLifetime
    {
        //视图非激活状态是否保存该实例,false则销毁该实例
        public bool KeepAlive => false;

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewA");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
           string addr= navigationContext.Parameters.GetValue<string>("Addr");
            navigationContext.Parameters.Add("Addr3", "ViewA");
        }
    }
}
 class ViewBViewModel : INavigationAware,IRegionMemberLifetime
    {
        public bool KeepAlive => true;

        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            //true:表示实例接收导航请求,即多次导航也只有一个实例
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewB");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            //接收来自 RequestNavigate(string regionName, string target, NavigationParameters navigationParameters);
            //的navigationParameters,也可以接收来自上一个视图的OnNavigatedFrom(NavigationContext navigationContext)
            //如果两个同时传参而key值相同则以 RequestNavigate为准
            string addr = navigationContext.Parameters.GetValue<string>("Addr");
        }
    }

效果:

  • ViewAKeepAlive==false所以ViewA在非激活状态时销毁;
  • ViewBKeepAlive==true所以ViewB在非激活状态没有进行销毁。
7.5,导航确认

通过实现接口IConfirmNavigationRequest完成导航确认,需要注意的是:导航确认是在离开本视图时进行,而不是进入本视图时进行

c# 复制代码
  class ViewBViewModel : INavigationAware,IRegionMemberLifetime,IConfirmNavigationRequest
    {
        #region 接口IRegionMemberLifetime的方法
        public bool KeepAlive => true;
        #endregion
        #region 接口IConfirmNavigationRequest的方法
        //从本视图切换到其他视图时执行
        //先执行ConfirmNavigationRequest,再执行OnNavigatedFrom
        public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
        {
            if(System.Windows.MessageBox.Show("是否离开此页面","询问", System.Windows.MessageBoxButton.YesNo)== System.Windows.MessageBoxResult.Yes)
            {
                continuationCallback?.Invoke(true);
            }
            else
            {
                continuationCallback?.Invoke(false);
            }
        }
        #endregion
        #region 接口INavigationAware的方法
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            //true:表示实例接收导航请求,即多次导航也只有一个实例
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewB");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
            //接收来自 RequestNavigate(string regionName, string target, NavigationParameters navigationParameters);
            //的navigationParameters,也可以接收来自上一个视图的OnNavigatedFrom(NavigationContext navigationContext)
            //如果两个同时传参而key值相同则以 RequestNavigate为准
            string addr = navigationContext.Parameters.GetValue<string>("Addr");
        }
        #endregion
    }
7.6,Tab区域的Header呈现与关闭
xaml 复制代码
<Window x:Class="lzg.PrismRegion.Navigation.Views.MainWindow"
        xmlns:prism="http://prismlibrary.com/"
        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:lzg.PrismRegion.Navigation.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <Grid Height="40" DockPanel.Dock="Top">
            <TextBlock FontSize="20" Text="{Binding Description}"></TextBlock>
        </Grid>
        <StackPanel DockPanel.Dock="Left" Width="80">
            <Button Content="ViewA" Command="{Binding OpenCommand}" CommandParameter="ViewA"></Button>
            <Button Content="ViewB" Command="{Binding OpenCommand}" CommandParameter="ViewB"></Button>
            
        </StackPanel>
        <Grid>
            <TabControl prism:RegionManager.RegionName="RegionView" >
                <TabControl.ItemContainerStyle>
                    <Style TargetType="TabItem">
                        <Setter Property="Header" Value="{Binding DataContext.Title}"></Setter>
                        <Setter Property="HeaderTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding}" Margin="3" VerticalAlignment="Center"></TextBlock>
                                        <Button Content="×" Command="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=Content.DataContext.DeleteCommand}" 
                                                CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=Content}"
                                                VerticalAlignment="Center" FontSize="16">
                                            <Button.Template>
                                                <ControlTemplate TargetType="Button">
                                                    <Border x:Name="Part_Back" Padding="2">
                                                        <ContentPresenter></ContentPresenter>
                                                    </Border>
                                                    <ControlTemplate.Triggers>
                                                        <Trigger Property="IsMouseOver" Value="True">
                                                            <Setter TargetName="Part_Back" Property="Background" Value="#12000000"></Setter>
                                                        </Trigger>
                                                    </ControlTemplate.Triggers>
                                                </ControlTemplate>
                                            </Button.Template>
                                        </Button>
                                    </StackPanel>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </TabControl.ItemContainerStyle>
            </TabControl>
        </Grid>
    </DockPanel>
</Window>
c# 复制代码
<Window x:Class="lzg.PrismRegion.Navigation.Views.MainWindow"
        xmlns:prism="http://prismlibrary.com/"
        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:lzg.PrismRegion.Navigation.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <Grid Height="40" DockPanel.Dock="Top">
            <TextBlock FontSize="20" Text="{Binding Description}"></TextBlock>
        </Grid>
        <StackPanel DockPanel.Dock="Left" Width="80">
            <Button Content="ViewA" Command="{Binding OpenCommand}" CommandParameter="ViewA"></Button>
            <Button Content="ViewB" Command="{Binding OpenCommand}" CommandParameter="ViewB"></Button>
            
        </StackPanel>
        <Grid>
            <TabControl prism:RegionManager.RegionName="RegionView" >
                <TabControl.ItemContainerStyle>
                    <Style TargetType="TabItem">
                        <Setter Property="Header" Value="{Binding DataContext.Title}"></Setter>
                        <Setter Property="HeaderTemplate">
                            <Setter.Value>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding}" Margin="3" VerticalAlignment="Center"></TextBlock>
                                        <Button Content="×" Command="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=Content.DataContext.DeleteCommand}" 
                                                CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=TabItem, Mode=FindAncestor}, Path=Content}"
                                                VerticalAlignment="Center" FontSize="16">
                                            <Button.Template>
                                                <ControlTemplate TargetType="Button">
                                                    <Border x:Name="Part_Back" Padding="2">
                                                        <ContentPresenter></ContentPresenter>
                                                    </Border>
                                                    <ControlTemplate.Triggers>
                                                        <Trigger Property="IsMouseOver" Value="True">
                                                            <Setter TargetName="Part_Back" Property="Background" Value="#12000000"></Setter>
                                                        </Trigger>
                                                    </ControlTemplate.Triggers>
                                                </ControlTemplate>
                                            </Button.Template>
                                        </Button>
                                    </StackPanel>
                                </DataTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </TabControl.ItemContainerStyle>
            </TabControl>
        </Grid>
    </DockPanel>
</Window>
c# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Prism.Regions;
namespace lzg.PrismRegion.Navigation.ViewModels.Pages
{
    class ViewAViewModel : INavigationAware,IRegionMemberLifetime
    {
        public string Title { get; set; } = "ViewA";
        public Prism.Commands.DelegateCommand<object> DeleteCommand { get; set; }
        //视图非激活状态是否保存该实例,false则销毁该实例
        public bool KeepAlive => true;
        public ViewAViewModel(Prism.Regions.IRegionManager regionManager)
        {
            DeleteCommand = new Prism.Commands.DelegateCommand<object>(obj =>
            {
                //删除当前视图
                regionManager.Regions["RegionView"].Remove(obj);
            });
        }
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }
        //从这个视图出发
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            navigationContext.Parameters.Add("Addr2", "来自于ViewA");
        }
        //到这个视图
        public void OnNavigatedTo(NavigationContext navigationContext)
        {
           string addr= navigationContext.Parameters.GetValue<string>("Addr");
            navigationContext.Parameters.Add("Addr3", "ViewA");
        }
    }
}
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lzg.PrismRegion.Navigation.ViewModels
{
    class MainWindowViewModel
    {
        public string Description { get; set; } = "视图导航案例";
        public MainWindowViewModel(Prism.Regions.IRegionManager regionManager)
        {
            OpenCommand = new Prism.Commands.DelegateCommand<string>(viewName =>
              {
                  //视图导航
                  //方法1,缺点:不能给视图传递参数,重复添加视图
                  // regionManager.RegisterViewWithRegion("RegionView", viewName);
                  // object obj = regionManager.Regions["RegionView"].Views.LastOrDefault(view => view.GetType().Name.Equals(viewName, StringComparison.InvariantCultureIgnoreCase));
                  // regionManager.Regions["RegionView"].Activate(obj);
                  //方法2,可以传递参数,可选择是否重复添加视图。缺点:ViewModel需要实现接口INavigationAware
                  //if (viewName == "ViewA")
                  //{
                      Prism.Regions.NavigationParameters paras = new Prism.Regions.NavigationParameters();
                      paras.Add("Addr", "来自于ManiWindow");
                      regionManager.RequestNavigate("RegionView", viewName, paras);
                  //}
                  //else
                  //{
                  //    regionManager.RequestNavigate("RegionView", viewName);
                  //}
                 
              });
        }
        public Prism.Commands.DelegateCommand<string> OpenCommand { get; set; }
    }
}

效果:

7.7,导航日志

关联接口: IJournalAware

该接口提供了PersistInHistory()方法作用是:为参与导航操作的对象提供了一种选择机制,使其能够避免被添加到"IRegionNavigationJournal"后退栈中。

C# 复制代码
 class ViewBViewModel : Prism.Regions.IJournalAware, Prism.Regions.INavigationAware
    {
        public string Title { get; set; } = "ViewB";
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public void OnNavigatedFrom(NavigationContext navigationContext)
        {

        }

        public void OnNavigatedTo(NavigationContext navigationContext)
        {

        }
        #region IJournalAware接口方法
        //确定当前对象是否将被添加到导航日志的后退栈中。
        public bool PersistInHistory()
        {
            //这里设置为false表示不保存B视图的导航历史
            return false;
        }
        #endregion
    }
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace lzg.PrismRegion.Journal.ViewModels
{
    class MainWindowViewModel
    {
        Prism.Regions.IRegionNavigationJournal journal;
        public MainWindowViewModel(Prism.Regions.IRegionManager regionManager)
        {
            NavigationCommand = new Prism.Commands.DelegateCommand<string>(viewName =>
              {
                  regionManager.RequestNavigate("ViewRegion", viewName);
                  Forward.RaiseCanExecuteChanged();
                  GoBack.RaiseCanExecuteChanged();
              });
            journal = regionManager.Regions["ViewRegion"].NavigationService.Journal;
            Forward = new Prism.Commands.DelegateCommand(DoForward,CanDoForward);                      
            GoBack = new Prism.Commands.DelegateCommand(DoGoBack,CanDoGoBack);
        }
        private bool CanDoGoBack()
        {
            return journal.CanGoBack;
        }
        private bool CanDoForward()
        {
             return journal.CanGoForward;
           // return true;
        }
        private void DoGoBack()
        {
            journal.GoBack();
            Forward.RaiseCanExecuteChanged();
        }
        private void DoForward()
        {
            journal.GoForward();
            GoBack.RaiseCanExecuteChanged();
        }
        public  Prism.Commands.DelegateCommand<string> NavigationCommand { get; set; }
      public  Prism.Commands.DelegateCommand Forward { get; set; }
      public  Prism.Commands.DelegateCommand GoBack { get; set; }
    }
}

8,复合命令CompositeCommand

作用: 一次执行多条命令

类名: Prism.Commands.CompositeCommand

8.1,注册复合指令

目的: 注册一个复合指令实例,使之成为容器。

C# 复制代码
public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<Views.MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //注册导航视图
            containerRegistry.RegisterForNavigation<Views.ViewA>("ViewA");
            containerRegistry.RegisterForNavigation<Views.ViewB>("ViewB");
            //注册复合命令单例
            containerRegistry.RegisterSingleton<Prism.Commands.CompositeCommand>();
        }
    }
8.2,进行容器注入
xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Composite.Views.ViewA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:lzg.PrismRegion.Composite.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button Content="ViewA" Command="{Binding OpenDialogCommand}" FontSize="20" Foreground="Red"></Button>
    </Grid>
</UserControl>
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lzg.PrismRegion.Composite.ViewModels
{
    class ViewAViewModel
    {
        public ViewAViewModel(Prism.Commands.CompositeCommand compositeCommand)
        {
            OpenDialogCommand = new Prism.Commands.DelegateCommand(() =>
            {
                System.Windows.MessageBox.Show("ViewA");
            });
            //将该命令添加到复合命令中
            compositeCommand.RegisterCommand(OpenDialogCommand);
        }
        public Prism.Commands.DelegateCommand OpenDialogCommand { get; set; }
    }
}
xaml 复制代码
<UserControl x:Class="lzg.PrismRegion.Composite.Views.ViewB"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:lzg.PrismRegion.Composite.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button Content="ViewB" Command="{Binding OpenDialogCommand}" FontSize="20" Foreground="Green"></Button>
    </Grid>
</UserControl>
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lzg.PrismRegion.Composite.ViewModels
{
    class ViewBViewModel
    {
        public ViewBViewModel(Prism.Commands.CompositeCommand compositeCommand)
        {
            OpenDialogCommand = new Prism.Commands.DelegateCommand(() =>
              {
                  System.Windows.MessageBox.Show("ViewB");
              });
            //将该命令添到复合命令中
            compositeCommand.RegisterCommand(OpenDialogCommand);
        }
        public Prism.Commands.DelegateCommand OpenDialogCommand { get; set; }
    }
}
8.3,调用复合指令
xaml 复制代码
<Window x:Class="lzg.PrismRegion.Composite.Views.MainWindow"
        xmlns:prism="http://prismlibrary.com/"
        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:lzg.PrismRegion.Composite.Views"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="137*"/>
            <ColumnDefinition Width="655*"/>
        </Grid.ColumnDefinitions>
        <StackPanel>
            <Button Content="打开视图" Command="{Binding OpenCommand}"></Button>
            <Button Content="同时弹出对话框" Command="{Binding CompositeCommand}"></Button>
        </StackPanel>
        <UniformGrid Columns="2" Grid.Column="1">
            <ContentControl prism:RegionManager.RegionName="LeftRegion"></ContentControl>
            <ContentControl prism:RegionManager.RegionName="RightRegion"></ContentControl>
        </UniformGrid>
    </Grid>
</Window>
C# 复制代码
 class MainWindowViewModel
    {
        public MainWindowViewModel(Prism.Commands.CompositeCommand compositeCommand,Prism.Regions.IRegionManager regionManager)
        {
            CompositeCommand = compositeCommand;
            OpenCommand = new Prism.Commands.DelegateCommand(() =>
              {
                  regionManager.RequestNavigate("LeftRegion", "ViewA");
                  regionManager.RequestNavigate("RightRegion", "ViewB");
              });
        }
        public Prism.Commands.DelegateCommand OpenCommand { get; set; }
        public Prism.Commands.CompositeCommand CompositeCommand { get; set; }
    }

9,模块化Module

9.1,创建Module
  • 创建类库项目

  • 引入Prism.DryIOC

  • 创建视图与基于IModule的类

    Xaml 复制代码
    <UserControl x:Class="lzg.PrismModule.ModuleA.ViewA"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:lzg.PrismModule.ModuleA"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
            <TextBlock FontSize="20" Foreground="Red" Text="{Binding Title}"></TextBlock>
        </Grid>
    </UserControl>
    c# 复制代码
    using Prism.Regions;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace lzg.PrismModule.ModuleA
    {
        class ViewAViewModel : Prism.Regions.INavigationAware
        {
            public string Title { get; set; } = "ViewA示例";
            public bool IsNavigationTarget(NavigationContext navigationContext)
            {
               return true;
            }
    
            public void OnNavigatedFrom(NavigationContext navigationContext)
            {
               
            }
    
            public void OnNavigatedTo(NavigationContext navigationContext)
            {
                
            }
        }
    }

    注册导航视图

    C# 复制代码
      public class ModuleA : Prism.Modularity.IModule
        {
            public void OnInitialized(IContainerProvider containerProvider)
            {
                
            }
    
            public void RegisterTypes(IContainerRegistry containerRegistry)
            {
                //在这里进行导航视图注册
                containerRegistry.RegisterForNavigation<ViewA>("ViewA");
            }
        }
9.2,加载Module
9.2.1,基于对象

添加类库引用,基于对象的Module加载,此方法并未解耦

C# 复制代码
public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {

        }
        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {
            base.ConfigureModuleCatalog(moduleCatalog);
            //方法1,这种需要添加链接库并没有完全解耦
            moduleCatalog.AddModule<lzg.PrismModule.ModuleA.ModuleA>();     
        }      
    }
9.2.2,基于app.config配置文件

基于app.config配置文件的Module加载,此方法实现了解耦

配置app.config文件

xml 复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<!--Prism.Modularity.ModulesConfigurationSection:模块配置节点类-->
		<!--Prism.Wpf:模块配置节点类所在的程序集Prism.Wpf.dll-->
		<section name="modules" type="Prism.Modularity.ModulesConfigurationSection,Prism.Wpf"/>
	</configSections>
	<modules>
		<!--assemblyFile:程序集文件名;moduleType:程序集限定名-->
		<module assemblyFile="dll/lzg.PrismModule.ModuleA.dll"
				 moduleName="ModuleA"
				 moduleType="lzg.PrismModule.ModuleA.ModuleA, lzg.PrismModule.ModuleA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
			
		</module>
	</modules>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
</configuration>

Module加载

C# 复制代码
using Prism.DryIoc;
using Prism.Ioc;
using Prism.Modularity;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace lzg.PrismModule
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {

        }
        protected override IModuleCatalog CreateModuleCatalog()
        {
            //创建一个基于app.config的Module
            return new ConfigurationModuleCatalog();
        }
    }
}
9.2.3,自动扫描目录

自动扫描指定的目录加载程序集

C# 复制代码
using Prism.DryIoc;
using Prism.Ioc;
using Prism.Modularity;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace lzg.PrismModule
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {

        }
     
        protected override IModuleCatalog CreateModuleCatalog()
        {
            //创建一个基于app.config的Module
            // return new ConfigurationModuleCatalog();
            // 扫描指定的目录,自动加载目录内的程序集
            return new DirectoryModuleCatalog
            {
                //自动扫描加载Modules文件夹下的程序集
                ModulePath="Modules"
            };
        }
    }
}
9.3,应用
xaml 复制代码
<Window x:Class="lzg.PrismModule.MainWindow"
        xmlns:prism="http://prismlibrary.com/"
        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:lzg.PrismModule"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="37*"/>
            <RowDefinition Height="383*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="119*"/>
            <ColumnDefinition Width="673*"/>
        </Grid.ColumnDefinitions>
        <Button Content="加载视图" Command="{Binding OpenCommand}"></Button>
        <ContentControl prism:RegionManager.RegionName="ViewRegion" Grid.Row="1" Grid.Column="1"></ContentControl>
    </Grid>
</Window>
C# 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace lzg.PrismModule
{
    class MainWindowViewModel
    {
        public MainWindowViewModel(Prism.Regions.IRegionManager regionManager)
        {
            OpenCommand = new Prism.Commands.DelegateCommand(() =>
              {
                  regionManager.RequestNavigate("ViewRegion", "ViewA");
              });
        }
        public Prism.Commands.DelegateCommand OpenCommand { get; set; }
    }
}

效果:

10,Demo链接

https://download.csdn.net/download/lingxiao16888/92382850

相关推荐
烛阴4 小时前
代码的灵魂:C# 方法全景解析(万字长文,建议收藏)
前端·c#
Tan_Ying_Y6 小时前
synchronized和ReentrantLock的区别是什么?他们的底层原理是什么?
开发语言·c#
gc_22996 小时前
学习C#调用Microsoft.Office.Interop.Word将Word转换为html
c#·html·word·interop.word
唐青枫8 小时前
C#.NET 集合表达式详解:新时代的集合初始化方式
c#·.net
Macbethad12 小时前
使用WPF编写一个Ethercat主站的程序
wpf
hez201014 小时前
TypedSql:在 C# 类型系统上实现一个 SQL 查询引擎
c#·.net·.net core·compiler
难搞靓仔14 小时前
WPF 弹出窗体Popup
wpf·popup
世洋Blog15 小时前
利用<<左移运算符优雅的设计游戏能力的任意组合和判断
游戏·unity·c#
曹牧15 小时前
C#中,#region和#endregion
开发语言·c#