复合程序的界面(UI)是由松耦合的组件(View)组成,Prism 提供了这种页面布局的解决方案。
下面是一个由不同模块的多个视图加载到主界面来布局的:
界面布局概念
一般主界面 (Shell) 是由 Regions 组成,但不关心 Region 的具体实现是什么。能够作为 Region 的容器的有:
- ContentControl
- ItemControl
- TabControl
Shell
Shell 定义了程序的整体外观,包含一个或多个 Region. 模块可以在 Region 里指定呈现的视图;Region 里可以放*UI元素,比如 背景、主菜单和工具栏。
Shell 可以定义样式和边框,还可以定义样式、模板和主题。
RegionManager
RegionManager 负责创建和维护一组 region,使用适配器将 region 和 control 进行关联。
RegionManager 可以通过代码 或 XAML 创建 region。Region 可以理解为是占位符,可以存放很多内容。RegionManager 提供了 RegionContext 属性,使得 regions 之间共享数据。
Region的具体实现
Region类是实现了 IRegion 接口的类,可以动态地加载 UI 元素。
RegionAdapter 负责创建 Region 并关联控件。
- ContentControlRegionAdapter - 适配System.Windows.Controls.ContentControl
- SelectorRegionAdapter - 适配System.Windows.Controls.Primitives.Selector 和 System.Windows.Controls.TabControl
- ItemsControlRegionAdapter - 适配System.Windows.Controls.ItemsControl
界面布局
来自不同 Modeule 的视图,在运行时会被创建和显示到特定的位置。有两种方式来实现这个功能。
View Discovery
在 ModuleManager 中通过 RegionViewRegistry 方法建立 RegionName 和 ViewType 之间的连接。在创建 Region 的时候会自动查找 ViewTypes 中与之关联的 View,并自动实例化并加载相应的视图。通过View Discovery无法控制何时加载和显示视图
通常在以下情况下使用View Discovery:
- 需要自动加载视图
- 区域中只包含视图的单个实例
View Injection
在视图注入中,编写代码使用 RegionManager 获取对 Region 的引用,然后将视图添加到其中。通常,这是在模块初始化或用户操作时完成的。
这样可以控制何时加载和显示视图,还可以从区域中删除视图。但无法将视图添加到尚未创建的 Region.
通常在以下情况下使用View Injection:
- 程序使用 Navigation API
- 程序需要对何时创建和显示视图进行控制
- 程序需要在一个区域中显示相同视图的多个实例, 每个实例绑定不同的数据
- 需要控制将视图添加到区域的哪个实例
Navigation
Prism Library 8 包含了对 Region 的导航,允许使用 URI 导航到具体的区域,从而简化了视图注入的过程。还可以导航到上一个视图。
复合程序布局核心场景
Shell
<!--Shell.xaml (WPF) -->
<Window x:Class="StockTraderRI.Shell">
<!--shell background -->
<Window.Background>
<ImageBrush ImageSource="Resources/background.png" Stretch="UniformToFill"/>
</Window.Background>
<Grid>
<!-- logo -->
<Canvas x:Name="Logo" ...>
<TextBlock Text="CFI" ... />
<TextBlock Text="STOCKTRADER" .../>
</Canvas>
<!-- main bar -->
<ItemsControl
x:Name="MainToolbar"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainToolBarRegion}"/>
<!-- content -->
<Grid>
<Controls:AnimatedTabControl
x:Name="PositionBuySellTab"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/>
</Grid>
<!-- details -->
<Grid>
<ContentControl
x:Name="ActionContent"
prism:RegionManager.RegionName="{x:Static inf:RegionNames.ActionRegion}"/>
</Grid>
<!-- sidebar -->
<Grid x:Name="SideGrid">
<Controls:ResearchControl
prism:RegionManager.RegionName="{x:Static inf:RegionNames.ResearchRegion}" />
</Grid>
</Grid>
</Window>
Region
Region 充当在运行时显示的一个或多个 View 的占位符,Module 可以定义 View 并添加到 Region,而无需知道 Region 显示的方式和位置。
除了可以在 XAML 中添加 Region ,还可以使用代码添加 region:
IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
RegionManager.SetRegionManager(this.ActionContent, regionManager);
RegionManager.SetRegionName(this.ActionContent, "ActionRegion");
View Discovery 加载视图的流程如下图所示:
Prism 库提供了一个标准的注册表,向区域注册视图:
// View discovery
this.regionManager.RegisterViewWithRegion("MainRegion", typeof(EmployeeView));
// View discovery
this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<EmployeeView>());
View Injection 加载视图的流程如下图所示:
// View injection
IRegion region = regionManager.Regions["MainRegion"];
var ordersView = container.Resolve<OrdersView>();
region.Add(ordersView, "OrdersView");
region.Activate(ordersView);
默认情况,视图按照注册和添加到区域的顺序显示。Prism 库提供了 ViewSortHint 属性,允许手动排序。