什么是Region
在我们的日常开发中,通常会将一个页面切割成不同的部分。如下一个页面,我们可以将其划分为头部、左侧目录、页面主体三个部分。
在Prism中,我们可以将这三个部分理解为三个区域(Region),而区域之中可以再细分区域。Region负责承担UI控件,其中内容并不固定,可以动态分配。
Prism中Region通过RegionManager进行管理。
使用Region的两种方式
方式1:
-
给页面中的内容控件设置RegionName
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" />
-
在页面的构造函数中注册Region中需要展示的内容,其中ViewA是定义在另一个xaml文件中的页面模块。
public MainView(IRegionManager regionManager) { InitializeComponent(); regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); }
方式2:
-
给页面的内容控件设置Name。
<ContentControl Grid.Row="1" x:Name="MainContent" />
-
在构造函数中通过SetRegionName方法设置RegionName,并注册Region中需要展示的内容。
public MainView(IRegionManager regionManager) { InitializeComponent(); RegionManager.SetRegionName(MainContent, "ContentRegion"); regionManager.RegisterViewWithRegion("ContentRegion", typeof(ViewA)); }
通过Region使View和ViewModel解耦
创建一个项目
项目只有一个窗体,但有两个页面模块,需要通过两个按钮进行页面切换。
在ViewModel设置一个object类型的对象Body来存放页面模块。
点击按钮后,通过Command中的委托方法来切换页面模块。
项目结构如下:
页面如下:
页面文件:MainView.xaml
<Window
x:Class="PrismDemo.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PrismDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
Title="MainWindow"
Width="800"
Height="450"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button
Margin="5"
Command="{Binding OpenCommand}"
CommandParameter="ViewA"
Content="模块A" />
<Button
Margin="5"
Command="{Binding OpenCommand}"
CommandParameter="ViewB"
Content="模块B" />
</StackPanel>
<ContentControl Grid.Row="1" Content="{Binding Body}" />
</Grid>
</Window>
MainViewModel.cs
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using PrismDemo.Views;
namespace PrismDemo.ViewModels
{
class MainViewModel : BindableBase
{
/**如下代码中,View与ViewModel耦合
*随着页面增多时,耦合情况会越来越严重,那么ViewModel将不堪重负
*可以使用Prism中的区域(Region)优化
*/
public DelegateCommand<string> OpenCommand { get; set; }
public MainViewModel()
{
OpenCommand = new DelegateCommand<string>(Open);
}
private object body;
public object Body
{
get { return body; }
set { body = value; RaisePropertyChanged(); }
}
private void Open(string obj)
{
switch (obj)
{
case "ViewA": Body = new ViewA(); break;
case "ViewB": Body = new ViewB(); break;
}
}
}
}
使用Region将View和ViewModel解耦
将上面MainView.xaml代码中的页面主体控件ContentControl更改如下:取消Body,并给ContentControl设置RegionName为ContentRegion。
<Grid>
<!--<ContentControl Grid.Row="1" Content="{Binding Body}" />-->
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" /></Grid>
在App.xaml.cs中,实现RegisterTypes方法,将两个View通过依赖注入注册为导航
using Prism.DryIoc;
using Prism.Ioc;
using PrismDemo.Views;
using System.Windows;
namespace PrismDemo
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
protected override Window CreateShell()
{
//从容器中获取MainView
return Container.Resolve<MainView>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//依赖注入
//此处可以给对应导航设置别名,不设置则默认为类名
containerRegistry.RegisterForNavigation<ViewA>("ViewA");
containerRegistry.RegisterForNavigation<ViewB>();
}
}
}
将MainViewModel代码更改如下:
- 取消原先用于存储View页面模板的Body属性,并引入IRegionManager来管理Regions。
- regionManager.Regions[“ContentRegion”]可以获取到页面中的Region
- .RequestNavigate(obj) 请求在容器中以及注册了的页面导航
class MainViewModel : BindableBase
{
private readonly IRegionManager regionManager;
public DelegateCommand<string> OpenCommand { get; set; }
public MainViewModel(IRegionManager regionManager)
{
OpenCommand = new DelegateCommand<string>(Open);
this.regionManager = regionManager;
}
/**通过App.xaml.cs中的RegisterTypes方法依赖注入了各个View
* 通过Region中的方法可以获取到这些View
* 不需要像上面注释的代码一样定义属性来变更页面模块
* 这样ViewModel代码就跟具体前端页面模块解耦了
*/
private void Open(string obj)
{
//首先通过IRegionManager接口获取当前全局定义的可用区域
//往这个区域动态地设置内容
//内容设置的方式是通过依赖注入的形式
regionManager.Regions["ContentRegion"].RequestNavigate(obj);
}
}