WPF棱镜 - 使用棱镜区域有什么意义?

时间:2011-11-01 17:45:40

标签: wpf design-patterns prism prism-4

我只是想知道地区的意义。我猜我不理解他们解决的问题

例如,我看到很多人使用区域作为导航区域,但为什么不只是将ItemsControl绑定到ObservableCollection而不是一个区域并将不同的导航元素加载到该区域?


一个现实世界的例子,它的使用/好处超过替代品会摇滚!

3 个答案:

答案 0 :(得分:18)

将RegionManager与EventAggregator进行比较,您将看到它的优势......

EventAggregator允许不同的组件发布/订阅事件,而不会相互耦合。 RegionManager也是如此......您可以将视图加载到某个区域,而无需其他视图知道其中发生了什么。它将你的观点彼此分离......这并不是说每个观点都应该彼此不知道......有时候观点应该知道另一个观点。


看看Microsoft Outlook(注意:我在这里做的事,包括名字,因为Outlook 不是用WPF编写,而是用C ++编写):

主用户界面将包含以下区域:

  • MenuRegion
  • NavigationRegion
  • ContentRegion
  • SideRegion

区域是在标准控件上定义的(因此您仍然需要标准控件),更具体地说,ItemsControl,ContentControl和Selector是开箱即用的(您可以将其他控件扩展为“区域支持”)。他们允许另一部分代码通过解析并将适当的视图加载到这些区域来管理区域。基本上,要把事情分开。

您的主要UI不需要知道关于您的应用的所有内容;相反,它只需要知道它有一个菜单,导航,内容和侧面区域。实际放置在区域中的哪些视图无关紧要。现在,这并不意味着每个视图都应该彼此分离。我稍后会谈到的。

那么,它实际上如何解耦?这是一个场景:单击导航控件中的日历图标。那么当你这样做会发生什么?

  1. NavigationView - 按钮(图标)绑定到ICommand,因此它调用ExecuteLoadCalendar()函数。
  2. NavigationViewModel - ExecuteLoadCalendar()函数使用EventAggregator宣布用户正在尝试启动日历。
  3. ContentController - ContentController订阅了LoadCalendarAggregateEvent,以便执行。在此,它使用CalendarView和区域名称解析/激活IRegionManager COUPLED )。 它应该通过抓取ICalendarView而不是CalendarView 来实现此目的。
  4. 除了ContentControllerCalendarView / ICalendarView之外,整个过程中每个部分都是分离的。当然,您可以通过NavigationViewNavigationViewModel / CalendarView 了解CalendarViewModel / ICommand和功能。好吧,“有点”与“他们做”不同,因为代码隐藏和视图模型代码永远不应该引用实际的CalendarView / CalendarViewModel对象。

    此外,我们可以通过使执行泛型来删除“种类”。它不具有ExecuteLoadCalendar()函数,而是具有LoadContent(NavigationItem item)函数,其中AggregateEvent有效负载是某种类型的标识,例如item.Name (String)(从数据库加载) ,XML等)说明他们点击了“日历”。 ContentController使用相同的数据来解析“日历”而不是ICalendarView(因为它真的不应该关心ContentRegion中解析/激活的接口/类型 - 它只是需要一个Object来激活)。我使用MEF,因此可以使用以下代码块实现:

    [Export("Calendar")]
    public class CalendarView : UserControl, ICalendarView { }
    

    那么,观点可以互相了解吗?是!例如,我的EmailUserControl有一个搜索栏/电子邮件列表以及一个预览窗格。这两个控件可以是EmailListUserControl,它由搜索栏和ItemsControl组成,还有EmailContentUserControl,它只是所选电子邮件的预览窗格。它们必须是单独的控件吗?不,但如果他们是,那么当我们在单独的窗口中打开电子邮件时,我们可以重用EmailContentUserControl。因此,这是EmailUserControl与2个不同视图(EmailListUserControlEmailContentUserControl)相关联的示例。


    为什么这与其他方法更好/不同:它将视图彼此分离(并防范需要了解视图的视图模型)。

答案 1 :(得分:16)

区域允许您在程序中定义为特定目的而存在的位置。例如,您可能有一个菜单区域或页脚区域。然后,您可以将这些特定区域的Views / ViewModel分离到它们自己的程序部分。

因此,不要让ApplicationViewModelMenuViewModel包含FooterViewModel属性,并让View将每个部分绑定到这些属性,而是为菜单和页脚设置单独的ViewModel,而您的ApplicationViewModel只会处理内容。这是在应用程序中分离一些逻辑边界的更好方法。

我个人认为地区过度使用和滥用。我几乎从不使用它们,除非我有一些与我的应用程序代码的其余部分无关的Header或Footer。它们也主要用于View-First开发,我更喜欢ViewModel-First。

答案 2 :(得分:2)

地区启用的情景

我浏览了这篇文章以获得答案:http://www.developmentalmadness.com/archive/2009/10/14/mvvm-and-prism-101-ndash-part-3-regions.aspx

据我所知,Region功能旨在在您既不是视图也不是视图模型的代码中启用View注册/注入。

ContentPresenter控件为例。如果您使用它而不是Region,则视图模型必须返回具体视图,以使主视图与其子视图保持不变。

如果您使用ItemsControl并将其绑定到视图模型上的任意数据,则需要指定在主视图上的DataTemplate中实例化哪些视图。

使用Region,您可以将视图注册到Dependency Injection容器中的Region。视图和相应的视图模型都不需要知道将在运行时使用的具体视图。它将由容器注入。

这使您可以完全将主视图与其子视图的任何信息分离,而不必强迫视图模型了解有关这些子视图的任何信息。

具体用例

这是多么有用,以及这将带来哪些具体方案,我不确定。我使用了ContentPresenter插件架构,但我不确定这种模型是否合适。使用插件模型,您希望将视图和视图模型绑定在一起,因此这种方法无需任何操作。

我认为如果你发现你有很多不相关的观点并希望将它们分开,那么它会最有效。通过一次仅注入部分视图和视图模型,将集成测试彼此隔离可能很有用。

我正在抓住吸引人的真实世界用例:)在几乎所有情况下你都可以简单地使用UserControl,并且可以放弃整个动态注册的事情,没有真正的失败。