上篇介绍了Region的基本应用,这篇接上篇,继续介绍关于Region的相关应用—RegionAdapter
示例代码下载
1.预先实现映射关系RegionAdapterMappings
RegionAdapterMappings对Control和RegionAdapter做了一个映射,这个映射是在Bootstrapper引导程序中完成的.
protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings() { RegionAdapterMappings regionAdapterMappings = Container.TryResolve<RegionAdapterMappings>(); if (regionAdapterMappings != null) { regionAdapterMappings.RegisterMapping(typeof(Selector), this.Container.Resolve<SelectorRegionAdapter>()); regionAdapterMappings.RegisterMapping(typeof(ItemsControl), this.Container.Resolve<ItemsControlRegionAdapter>()); regionAdapterMappings.RegisterMapping(typeof(ContentControl), this.Container.Resolve<ContentControlRegionAdapter>()); } return regionAdapterMappings; }
这里提供了三种控件支持,在上篇也有交代.RegionAdapter必须实现IRegionAdapter接口
2.在注册Region时寻找RegionAdapter
<StackPanel cal:RegionManager.RegionName="MainRegion"/>
以上的定义是错误的,因为在RegionAdapterMappings无法找到StackPanel和RegionAdapter的映射关系.以上附加属性的设置会尝试执行以下代码
protected virtual IRegion CreateRegion(DependencyObject targetElement, string regionName) { // Build the region IRegionAdapter regionAdapter = this.regionAdapterMappings.GetMapping(targetElement.GetType()); IRegion region = regionAdapter.Initialize(targetElement, regionName); return region; }
为了支持StackPanel,我们可以尝试为StackPanel定义一个实现IRegionAdapter的区域适配器.
3.自定义RegionAdapter
以下为StackPanel定义RegionAdapter为例子
3.1.定义一个实现IRegionAdapter的适配器,在这里可以控制StackPanel对象
public class StackPanelRegionAdapter : IRegionAdapter { public IRegion Initialize(object regionTarget, string regionName) { StackPanel panel = regionTarget as StackPanel; panel.Children.Add(new Label() { Content = "hello" }); return new Region(); } }
3.2 重写Bootstrapper的ConfigureRegionAdapterMappings方法,注册映射关系
protected override RegionAdapterMappings ConfigureRegionAdapterMappings() { RegionAdapterMappings regionAdapterMappings = base.ConfigureRegionAdapterMappings(); regionAdapterMappings.RegisterMapping(typeof(StackPanel), this.Container.Resolve<StackPanelRegionAdapter>()); return regionAdapterMappings; }
现在就可以在StackPanel注册Region了
<StackPanel cal:RegionManager.RegionName="MainRegion"/>
4.根据Region的操作变更UI
我们来看一下IRegion接口
关于Region的基本应用在上篇已经介绍,主要用于对View的一些操作,之后ActiveViews和Views集合会发生变化,这两个集合是IViewsCollection类型并支持INotifyCollectionChanged接口.控件可以根据IRegion的信息变更做出变更.
以上StackPanelRegionAdapter重构后如下,看到这里再回头看上篇就能更好的理解Activate这些方法的作用了.
public class StackPanelRegionAdapter : IRegionAdapter { public IRegion Initialize(object regionTarget, string regionName) { StackPanel panel = regionTarget as StackPanel; AllActiveRegion region = new AllActiveRegion(); region.Name = regionName; region.ActiveViews.CollectionChanged += delegate { panel.Children.Clear(); foreach (var item in region.ActiveViews) { panel.Children.Add(item as UIElement); } }; return region; } }
请注意,以上代码还无法执行虽然完成了适配,但当注册Region以后,还需要将Region添加到RegionManager中,我们还需要做一些额外的操作.prism提供内置的RegionAdapterBase抽象类,实现了IRegionAdapter,帮助我们做了一些额外的工作.我们可以从这个抽象类继承.
我们来看RegionAdapterBase实现的Initialize方法,给我们制定了模板,我们就重写这些方法就可以了
public IRegion Initialize(T regionTarget, string regionName) { if (regionName == null) throw new ArgumentNullException("regionName"); IRegion region = CreateRegion(); region.Name = regionName; SetObservableRegionOnHostingControl(region, regionTarget); Adapt(region, regionTarget); AttachBehaviors(region, regionTarget); AttachDefaultBehaviors(region, regionTarget); return region; }
一般情况下我们只需要重写Adapt和CreateRegion即可.先重构如下
public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel> { public StackPanelRegionAdapter(IRegionBehaviorFactory defaultBehaviors) : base(defaultBehaviors) { } protected override void Adapt(IRegion region, StackPanel regionTarget) { region.ActiveViews.CollectionChanged += delegate { regionTarget.Children.Clear(); foreach (var item in region.ActiveViews) { regionTarget.Children.Add(item as UIElement); } }; } protected override IRegion CreateRegion() { return new AllActiveRegion(); } }
内置实现IRegion有三个类型,如ContentControl并不是一个集合控件,则会创建一个SingelActiveRegion,集合控件则创建AllActiveRegion
在RegionAdapter中出现了RegionBehavior,将在下篇介绍此应用.下图解释了以上执行过程.