5. Prism系列之区域管理器

Prism系列之区域管理器


文章目录

  • Prism系列之区域管理器
    • 一、区域管理器
    • 二、区域创建与视图的注入
      • 1. ViewDiscovery
      • 2. ViewInjection
    • 三、激活与失效视图
      • 1. Activate和Deactivate
      • 2. 监控视图激活状态
      • 3. Add和Remove
    • 四、自定义区域适配器
      • 1. 创建自定义适配器
      • 2. 注册映射
      • 3. 创建区域


一、区域管理器

这篇文章将会讲解之前项目中用到的利用区域管理器更好的对我们的View进行管理,同样的我们来看看官方给出的模型图:

在这里插入图片描述

大致一个区域管理器RegionMannager对一个控件创建区域的要点:

  1. 创建Region的控件必须包含一个RegionAdapter适配器
  2. Region是依赖在具有RegionAdapter控件身上的

其实后来我去看了下官方的介绍和源码,默认RegionAdapter是有三个,且还支持自定义RegionAdapter,因此在官方的模型图之间我做了点补充:

在这里插入图片描述

二、区域创建与视图的注入

我们先来看看我们之前项目的区域的划分,以及如何创建区域并且把View注入到区域中:

在这里插入图片描述

把整个主窗体划分了四个区域:

  • ShowSearchPatientRegion:注入了ShowSearchPatient视图
  • PatientListRegion:注入了PatientList视图
  • FlyoutRegion:注入了PatientDetailSearchMedicine视图
  • ShowSearchPatientRegion:注入了ShowSearchPatient视图

Prism中,我们有两种方式去实现区域创建和视图注入:

  1. ViewDiscovery
  2. ViewInjection

1. ViewDiscovery

我们截取其中PatientListRegion的创建和视图注入的代码

MainWindow.xaml:

<ContentControl Grid.Row="2" prism:RegionManager.RegionName="PatientListRegion" Margin="10"/>

这里相当于在后台MainWindow.cs:

RegionManager.SetRegionName(ContentControl, "PatientListRegion");

PatientModule.cs:

 public class PatientModule : IModule{public void OnInitialized(IContainerProvider containerProvider){var regionManager = containerProvider.Resolve<IRegionManager>();//PatientListregionManager.RegisterViewWithRegion(RegionNames.PatientListRegion, typeof(PatientList));//PatientDetail-FlyoutregionManager.RegisterViewWithRegion(RegionNames.FlyoutRegion, typeof(PatientDetail));}public void RegisterTypes(IContainerRegistry containerRegistry){}}

2. ViewInjection

我们在MainWindow窗体的Loaded事件中使用ViewInjection方式注入视图PatientList

MainWindow.xaml:

  <i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding LoadingCommand}"/>/i:EventTrigger></i:Interaction.Triggers>

MainWindowViewModel.cs:

private IRegionManager _regionManager;
private IRegion _paientListRegion;        
private PatientList _patientListView;private DelegateCommand _loadingCommand;
public DelegateCommand LoadingCommand =>_loadingCommand ?? (_loadingCommand = new DelegateCommand(ExecuteLoadingCommand));void ExecuteLoadingCommand()
{_regionManager = CommonServiceLocator.ServiceLocator.Current.GetInstance<IRegionManager>();_paientListRegion = _regionManager.Regions[RegionNames.PatientListRegion];_patientListView = CommonServiceLocator.ServiceLocator.Current.GetInstance<PatientList>();_paientListRegion.Add(_patientListView);}

我们可以明显的感觉到两种方式的不同,ViewDiscovery方式是自动地实例化视图并且加载出来,而ViewInjection方式则是可以手动控制注入视图和加载视图的时机(上述例子是通过Loaded事件),官方对于两者的推荐使用场景如下:

ViewDiscovery:

  • 需要或要求自动加载视图
  • 视图的单个实例将加载到该区域中

ViewInjection:

  • 需要显式或编程控制何时创建和显示视图,或者您需要从区域中删除视图
  • 需要在区域中显示相同视图的多个实例,其中每个视图实例都绑定到不同的数据
  • 需要控制添加视图的区域的哪个实例
  • 应用程序使用导航API

三、激活与失效视图

1. Activate和Deactivate

首先我们需要控制PatientListMedicineMainContent两个视图的激活情况,上代码:

MainWindow.xaml:

<StackPanel Grid.Row="1"><Button  Content="Load MedicineModule" FontSize="25"  Margin="5" Command="{Binding LoadMedicineModuleCommand}"/><UniformGrid Margin="5"><Button Content="ActivePaientList" Margin="5" Command="{Binding ActivePaientListCommand}"/><Button Content="DeactivePaientList" Margin="5" Command="{Binding DeactivePaientListCommand}"/><Button Content="ActiveMedicineList" Margin="5" Command="{Binding ActiveMedicineListCommand}"/><Button Content="DeactiveMedicineList" Margin="5" Command="{Binding DeactiveMedicineListCommand}"/></UniformGrid>
</StackPanel><ContentControl Grid.Row="2" prism:RegionManager.RegionName="PatientListRegion" Margin="10"/>
<ContentControl Grid.Row="3" prism:RegionManager.RegionName="MedicineMainContentRegion"/>

MainWindowViewModel.cs:

  private IRegionManager _regionManager;private IRegion _paientListRegion;private IRegion _medicineListRegion;private PatientList _patientListView;private MedicineMainContent _medicineMainContentView;private bool _isCanExcute = false;public bool IsCanExcute{get { return _isCanExcute; }set { SetProperty(ref _isCanExcute, value); }}private DelegateCommand _loadingCommand;public DelegateCommand LoadingCommand =>_loadingCommand ?? (_loadingCommand = new DelegateCommand(ExecuteLoadingCommand));private DelegateCommand _activePaientListCommand;public DelegateCommand ActivePaientListCommand =>_activePaientListCommand ?? (_activePaientListCommand = new DelegateCommand(ExecuteActivePaientListCommand));private DelegateCommand _deactivePaientListCommand;public DelegateCommand DeactivePaientListCommand =>_deactivePaientListCommand ?? (_deactivePaientListCommand = new DelegateCommand(ExecuteDeactivePaientListCommand));private DelegateCommand _activeMedicineListCommand;public DelegateCommand ActiveMedicineListCommand =>_activeMedicineListCommand ?? (_activeMedicineListCommand = new DelegateCommand(ExecuteActiveMedicineListCommand).ObservesCanExecute(() => IsCanExcute));private DelegateCommand _deactiveMedicineListCommand;public DelegateCommand DeactiveMedicineListCommand =>_deactiveMedicineListCommand ?? (_deactiveMedicineListCommand = new DelegateCommand(ExecuteDeactiveMedicineListCommand).ObservesCanExecute(() => IsCanExcute));private DelegateCommand _loadMedicineModuleCommand;public DelegateCommand LoadMedicineModuleCommand =>_loadMedicineModuleCommand ?? (_loadMedicineModuleCommand = new DelegateCommand(ExecuteLoadMedicineModuleCommand));/// <summary>/// 窗体加载事件/// </summary>void ExecuteLoadingCommand(){_regionManager = CommonServiceLocator.ServiceLocator.Current.GetInstance<IRegionManager>();_paientListRegion = _regionManager.Regions[RegionNames.PatientListRegion];_patientListView = CommonServiceLocator.ServiceLocator.Current.GetInstance<PatientList>();_paientListRegion.Add(_patientListView);_medicineListRegion = _regionManager.Regions[RegionNames.MedicineMainContentRegion];}/// <summary>/// 失效medicineMainContent视图/// </summary>void ExecuteDeactiveMedicineListCommand(){_medicineListRegion.Deactivate(_medicineMainContentView);}/// <summary>/// 激活medicineMainContent视图/// </summary>void ExecuteActiveMedicineListCommand(){_medicineListRegion.Activate(_medicineMainContentView);}/// <summary>/// 失效patientList视图/// </summary>void ExecuteDeactivePaientListCommand(){_paientListRegion.Deactivate(_patientListView);}/// <summary>/// 激活patientList视图/// </summary>void ExecuteActivePaientListCommand(){_paientListRegion.Activate(_patientListView);}/// <summary>/// 加载MedicineModule/// </summary>void ExecuteLoadMedicineModuleCommand(){_moduleManager.LoadModule("MedicineModule");_medicineMainContentView = (MedicineMainContent)_medicineListRegion.Views.Where(t => t.GetType() == typeof(MedicineMainContent)).FirstOrDefault();this.IsCanExcute = true;}

2. 监控视图激活状态

Prism其中还支持监控视图的激活状态,是通过在View中继承IActiveAware来实现的,我们以监控其中MedicineMainContent视图的激活状态为例子:

MedicineMainContentViewModel.cs:

 public class MedicineMainContentViewModel : BindableBase,IActiveAware{public event EventHandler IsActiveChanged;bool _isActive;public bool IsActive{get { return _isActive; }set{_isActive = value;if (_isActive){MessageBox.Show("视图被激活了");}else{MessageBox.Show("视图失效了");}IsActiveChanged?.Invoke(this, new EventArgs());}}}

3. Add和Remove

上述例子用的是ContentControl,我们再用一个ItemsControl的例子,代码如下:

MainWindow.xaml:

  <metro:MetroWindow.RightWindowCommands><metro:WindowCommands x:Name="rightWindowCommandsRegion" /></metro:MetroWindow.RightWindowCommands>

MainWindow.cs:

 public MainWindow(){InitializeComponent();var regionManager= ServiceLocator.Current.GetInstance<IRegionManager>();if (regionManager != null){SetRegionManager(regionManager, this.flyoutsControlRegion, RegionNames.FlyoutRegion);//创建WindowCommands控件区域SetRegionManager(regionManager, this.rightWindowCommandsRegion, RegionNames.ShowSearchPatientRegion);}}void SetRegionManager(IRegionManager regionManager, DependencyObject regionTarget, string regionName){RegionManager.SetRegionName(regionTarget, regionName);RegionManager.SetRegionManager(regionTarget, regionManager);}

ShowSearchPatient.xaml:

<StackPanel x:Class="PrismMetroSample.MedicineModule.Views.ShowSearchPatient"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:prism="http://prismlibrary.com/"  xmlns:const="clr-namespace:PrismMetroSample.Infrastructure.Constants;assembly=PrismMetroSample.Infrastructure"Orientation="Horizontal"    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"prism:ViewModelLocator.AutoWireViewModel="True"><i:Interaction.Triggers><i:EventTrigger EventName="Loaded"><i:InvokeCommandAction Command="{Binding ShowSearchLoadingCommand}"/></i:EventTrigger></i:Interaction.Triggers><CheckBox IsChecked="{Binding IsShow}"/><Button Command="{Binding ApplicationCommands.ShowCommand}" CommandParameter="{x:Static const:FlyoutNames.SearchMedicineFlyout}"><StackPanel Orientation="Horizontal"><Image Height="20" Source="pack://application:,,,/PrismMetroSample.Infrastructure;Component/Assets/Photos/按钮.png"/><TextBlock Text="Show" FontWeight="Bold" FontSize="15" VerticalAlignment="Center"/></StackPanel></Button>
</StackPanel>

ShowSearchPatientViewModel.cs:

 private IApplicationCommands _applicationCommands;private readonly IRegionManager _regionManager;private ShowSearchPatient _showSearchPatientView;private IRegion _region;public IApplicationCommands ApplicationCommands{get { return _applicationCommands; }set { SetProperty(ref _applicationCommands, value); }}private bool _isShow=true;public bool IsShow{get { return _isShow=true; }set { SetProperty(ref _isShow, value);if (_isShow){ActiveShowSearchPatient();}else{DeactiveShowSearchPaitent();}}}private DelegateCommand _showSearchLoadingCommand;public DelegateCommand ShowSearchLoadingCommand =>_showSearchLoadingCommand ?? (_showSearchLoadingCommand = new DelegateCommand(ExecuteShowSearchLoadingCommand));void ExecuteShowSearchLoadingCommand(){_region = _regionManager.Regions[RegionNames.ShowSearchPatientRegion];_showSearchPatientView = (ShowSearchPatient)_region.Views.Where(t => t.GetType() == typeof(ShowSearchPatient)).FirstOrDefault();}public ShowSearchPatientViewModel(IApplicationCommands applicationCommands,IRegionManager regionManager){this.ApplicationCommands = applicationCommands;_regionManager = regionManager;}/// <summary>/// 激活视图/// </summary>private void ActiveShowSearchPatient(){if (!_region.ActiveViews.Contains(_showSearchPatientView)){_region.Add(_showSearchPatientView);}         }/// <summary>/// 失效视图/// </summary>private async void DeactiveShowSearchPaitent(){_region.Remove(_showSearchPatientView);await Task.Delay(2000);IsShow = true;}

这里的WindowCommands 的继承链为:WindowCommands <-- ToolBar <-- HeaderedItemsControl <–ItemsControl,因此由于Prism默认的适配器有ItemsControlRegionAdapter,因此其子类也继承了其行为。

这里重点归纳一下:

  • 当进行模块化时,加载完模块才会去注入视图到区域(可参考MedicineModule视图加载顺序)
  • ContentControl控件由于Content只能显示一个,在其区域中可以通过Activate和Deactivate方法来控制显示哪个视图,其行为是由ContentControlRegionAdapter适配器控制
  • ItemsControl控件及其子控件由于显示一个集合视图,默认全部集合视图是激活的,这时候不能通过Activate和Deactivate方式来控制(会报错),通过Add和Remove来控制要显示哪些视图,其行为是由ItemsControlRegionAdapter适配器控制
  • 这里没讲到Selector控件,因为也是继承自ItemsControl,因此其SelectorRegionAdapter适配器和ItemsControlRegionAdapter适配器异曲同工
  • 可以通过继承IActiveAware接口来监控视图激活状态

四、自定义区域适配器

Prism有三个默认的区域适配器:ItemsControlRegionAdapter,ContentControlRegionAdapter,SelectorRegionAdapter,且支持自定义区域适配器,现在我们来自定义一下适配器。

1. 创建自定义适配器

UniformGridRegionAdapter.cs:

public class UniformGridRegionAdapter : RegionAdapterBase<UniformGrid>
{public UniformGridRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory){}protected override void Adapt(IRegion region, UniformGrid regionTarget){region.Views.CollectionChanged += (s, e) =>{if (e.Action==System.Collections.Specialized.NotifyCollectionChangedAction.Add){foreach (FrameworkElement element in e.NewItems){regionTarget.Children.Add(element);}}};}protected override IRegion CreateRegion(){return new AllActiveRegion();}}

2. 注册映射

App.cs:

protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{base.ConfigureRegionAdapterMappings(regionAdapterMappings);//为UniformGrid控件注册适配器映射regionAdapterMappings.RegisterMapping(typeof(UniformGrid),Container.Resolve<UniformGridRegionAdapter>());
}

3. 创建区域

MainWindow.xaml:

<UniformGrid Margin="5" prism:RegionManager.RegionName="UniformContentRegion" Columns="2"><Button Content="ActivePaientList" Margin="5" Command="{Binding ActivePaientListCommand}"/><Button Content="DeactivePaientList" Margin="5" Command="{Binding DeactivePaientListCommand}"/><Button Content="ActiveMedicineList" Margin="5" Command="{Binding ActiveMedicineListCommand}"/><Button Content="DeactiveMedicineList" Margin="5" Command="{Binding DeactiveMedicineListCommand}"/>
</UniformGrid>

我们可以看到我们为UniformGrid创建区域适配器,并且注册后,也能够为UniformGrid控件创建区域,并且注入视图显示,如果没有该区域适配器,则是会报错。

回到顶部


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/286275.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

showdoc使用

使用 通过上篇文章安装得到的访问地址&#xff0c;可以登陆到h5页面中 点击客户端&#xff0c;进入到页面 下载完成之后&#xff0c;注册账号&#xff0c;选择自己的私域地址&#xff08;http://服务器IP:4999&#xff09;之后&#xff0c;就可以开始团队协作了

Android13音频录制适配

Android13音频录制适配 前言&#xff1a; 之前写过一篇音频录制的文章&#xff0c;当时是在Android10以下的手机可以成功录制和播放&#xff0c;但是Android10及以上手机提示创建文件失败&#xff0c;最近做过Android13的适配&#xff0c;索性一起把之前的录音也适配了&#…

【JetBrains】将Gateway中的GoLand回滚到无bug旧版本

问题背景 2023-12-15 我把 Gateway 中使用的 GoLand 从 2023.2.x 升级到了 2023.3 &#xff0c;然后编辑文件过程中输入时时不时会显示错误信息&#xff0c;然后就会进入无法输入&#xff08;键入也不会看到增加字符&#xff09;但能粘贴的奇怪状态。 问题解决 升级到 2023.…

基于ssm楚师师生健康管理系统设计与实现论文

楚师师生健康管理系统设计实现 摘要 随着信息互联网购物的飞速发展&#xff0c;一般企业都去创建属于自己的管理系统。本文介绍了楚师师生健康管理系统的开发全过程。通过分析企业对于楚师师生健康管理系统的需求&#xff0c;创建了一个计算机管理楚师师生健康管理系统的方案…

playwright进阶问题,with sync_playwright() as p中的p是什么类型您知道吗?

playwritght中with as的用法 最近在看playwritght 的源码&#xff0c;大家都知道运行playwright的基础代码如下&#xff1a; with sync_playwright() as p:browser p.chromium.launch(channel"chrome", headlessFalse)page browser.new_page()page.goto("ht…

Zotero 7 安装并彻底解决“无法安装插件。它可能无法与该版本的 Zotero 兼容“。以及解决“此翻译引擎不可用,可能是密钥错误“的问题

Zotero 7 安装并彻底解决"无法安装插件。它可能无法与该版本的 Zotero 兼容"。以及解决"此翻译引擎不可用&#xff0c;可能是密钥错误"的问题 &#xff01;&#xff01;&#xff01;不要直接在Zotero 6上安装翻译插件&#xff0c;将会版本不兼容&#xff0…

【01】GeoScene生产海图或者电子航道图

1.1 什么是电子海图制图模块 GeoScene海事模块是一个用于管理和制作符合国际水文组织&#xff08;IHO&#xff09;S-100系列标准和S-57标准的海事数据的系统。提供了S-100和S-57工具&#xff0c;用于加载基于S-100的要素目录、创建基于S-57传输结构的数据、输入数据、符号化数…

【数据结构和算法】 K 和数对的最大数目

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 方法一&#xff1a;双指针排序 三、代码 3.1 方法一&#xff1a;双指针排序 3.2 方法二&#xff1…

羊奶vs牛奶,羊大师告诉你谁是更营养的选择?

羊奶vs牛奶&#xff0c;羊大师告诉你谁是更营养的选择&#xff1f; 羊奶和牛奶是两种常见的乳制品&#xff0c;它们不仅在口味上有所差异&#xff0c;而且在营养成分方面也存在一些差异。本文将对羊奶和牛奶的营养成分进行全面对比&#xff0c;旨在帮助读者更好地了解这两种乳…

【1.9计算机组成与体系结构】总线

目录 1.总线的定义2.总线的分类 1.总线的定义 √ 总线是一组能为多个部件分时共享的公共信息传送线路。 &#x1f535; 共享 &#x1f535; 分时:是指同一时刻仅允许一个部件向总线发送信息&#xff0c;但允许多个部件同时从总线上接收相同的信息。 √ 串行总线 (适合长距离传…

【功能更新】支持文档合并导出PDF/HTML格式;线上文章SEO设置能力优化

HelpLook功能更新速览&#x1f447; 文档管理能力&#xff1a; 1. 导出支持多篇文档合在一个HTML文件 2. 支持下载附件时保留原始文件名 3. 主页“推荐文章”支持添加外链 4. 文章URL根据标题自动生成 5. 文章支持添加“作者” 6. 博客模版支持置顶文章 1.导出支持多篇文…

Linux之grep、sed、awk

目录 1.grep 2.sed 3.awk 1.grep grep 擅长过滤查找&#xff0c;按行进行过滤 例&#xff1a; 当有用户对我们的主机进行爆破攻击时&#xff0c;我们可以使用grep将 ip 查找出来&#xff0c;进行封锁等处理 在 /var/log 目录下的 secure 文件中存放在用户登录连接信息&am…