
我们晓得,每个Module中,实现了IModule接口的Module类,都要实现该接口的Initialize方法,一方面要注册一些自定义的接口和实现了该接口的类,为接下来的依赖注入做准备;另一方面,就是为Region加载VIEw并显示(初始化VIEw)。
加载VIEw的方式,分为VIEw Injection和VIEw discovery两类,各有千秋。
1. VIEw Injection,指的是RegionManager,它的属性Regions,这是一个集合类RegionCollection,同时还实现了基于Regionname的内部索引。于是,我们可以这样编写代码:
VIEw-first:
this.regionManager.Regions["MainRegion"].Add(new HelloWorldVIEw());
Presenter-first:
this.regionManager.Regions["MainRegion"].Add(this.container.Resolve<HelloWorldPresenter>().VIEw);
有关VIEw-first和Presenter-first的概念,我们在下一节中专门介绍。
VIEw Injection的视图如下,有点像中介者模式吧,那个Registry就是一个Mediator:
注意,VIEw Injection只适用于RegionManager,不适用于RegionVIEwRegistry,原因么,看我下面的分析。
2. VIEw discovery,指的是RegionVIEwRegistry的RegisterVIEwWithRegion方法,有2个重载:
public voID RegisterVIEwWithRegion(string regionname,Type vIEwType)
{
this.RegisterVIEwWithRegion(regionname,() => this.CreateInstance(vIEwType));
}
public voID RegisterVIEwWithRegion(string regionname,Func<object> getContentDelegate)
{
this.registeredContent.Add(regionname,getContentDelegate);
this.OnContentRegistered(new VIEwRegisteredEventArgs(regionname,getContentDelegate));
}
我们看到,第1个方法是基于第2个方法的,就是把Regionname和一个delegate(用于创建VIEw的一个实例)同时注册到字典ListDictionary<string,Func<object>>和委托链WeakDelegatesManager中。
于是我们可以这样编写代码:
VIEw-first:
this. RegionVIEwRegistry.RegisterVIEwWithRegion("MainRegion",typeof(VIEws.HelloWorldVIEw));
Presenter-first:
this. RegionVIEwRegistry.RegisterVIEwWithRegion("MainRegion",
() => this.container.Resolve<IHelloWorldPresenter>().VIEw);
有关VIEw-first和Presenter-first的概念,我们在下一节中专门介绍。
VIEw discovery的视图如下,看这个图让我想起了GOF中的注册工厂:
Prism文档中P18说到,VIEw discovery适用于V-first,而VIEw Injection同时适用于V-first和P-first。这是不恰当的。看了我上面的分析和代码,就会发现VIEw discovery也有以P-first方式实现的,而且也是很常用的。
VIEw Injection和VIEw discovery,本来就是2个不同类——RegionManager和RegionVIEwRegistry的不同实现方式,连存储结构都不同,前者是集合,后者是字典。相对而言,前者的实现更直接一些(来一个招呼一个),后者比较绕(先对号入座,然后再用到谁招呼谁)。
存储结构的不同,使得二者在性能上有很大差异。RegionManager的Regions属性是一个集合,所以可以手动添加或移除Region中的VIEw(使用集合的Add或Remove方法),尤其是移除功能,可以释放不再使用的内存。
相对而言,RegionVIEwRegistry在内部使用字典来存储VIEw,它的RegisterVIEwWithRegion方法就是把VIEw添加到这个字典中,但是,由于这个字典是私有的,不对外暴露,所以我们无法使用它的Remove方法来移除VIEw。这是因为,我们存储到字典中的VIEw都是弱引用,再回顾一下:
this. RegionVIEwRegistry.RegisterVIEwWithRegion("MainRegion",typeof(VIEws.HelloWorldVIEw));
这里typeof(VIEws.HelloWorldVIEw)就是一个弱引用,我们知道,.NET会自动回收不再使用的内存,所以,理想情况下,不再使用这个VIEw时,该VIEw所占的内存就会被自动回收了。但是,自动回收内存在什么时候发生呢?没人知道。所以,系统越来越慢,就是因为RegionVIEwRegistry的这个方法导致的。
既然不好用,那为什么还要设计出RegionVIEwRegistry呢?
说起来话长了。这要从Prism的第1版说起。话说,那时Prism中只有VIEw Injection机制,也就是说,只有RegionManager类。后来,大家发现RegionManager类也有不好的地方,就是在嵌套Region的时候,每一级Region中都要写点Regions[“Regionname”].Add方法,而且还要care层次间的关系,是不是觉得很麻烦?而且Prism经常会报错说找不到Regionname,以致于抛出异常(关于这一点,请参见我的另一篇文章)。为了方便开发,p&p小组在Prism第2版中提供了RegionVIEwRegistry类,及其RegisterVIEwWithRegion方法,于是我们可以在任何地方使用该方法,而不需要在各自的VIEw中编写相应的代码。但是,简单是要付出代价的,那就是性能,上文已经分析过。
同时,Prism框架把RegisterVIEwWithRegion也作为扩展方法添加到了RegionManager类中,实际上还是调用RegionVIEwRegistry类的RegisterVIEwWithRegion方法。于是,形成了一个组合关系。
本来设计思想是蛮好的,可以屏蔽RegionVIEwRegistry类,对ClIEnt而言,只有RegionManager类,它同时具有RegisterVIEwWithRegion方法和Regions[“Regionname”]属性(前者是弱引用方式,后者是强引用方式)。
但是,不知是微软p & p的那个DPE大脑进水,在Prism文档和示例又同时使用了RegionVIEwRegistry的RegisterVIEwWithRegion方法。这就违背了设计的初衷。于是,我们糊涂了,不知道什么时候该使用哪一个类的哪一个方法,甚至开始怀疑人生。
总结以上是内存溢出为你收集整理的Prism研究(for WPF & Silverlight)7.View Injection和View Discovery全部内容,希望文章能够帮你解决Prism研究(for WPF & Silverlight)7.View Injection和View Discovery所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)