我只是想知道区域的意义是什么。我想我不明白他们解决的问题。
例如,我看到很多人使用区域作为导航区域,但是为什么不将 ItemsControl 绑定到 ObservableCollection 而不是拥有一个区域并将不同的导航元素加载到该区域中呢?
它在替代品上的使用/好处的真实示例将会震撼!
我只是想知道区域的意义是什么。我想我不明白他们解决的问题。
例如,我看到很多人使用区域作为导航区域,但是为什么不将 ItemsControl 绑定到 ObservableCollection 而不是拥有一个区域并将不同的导航元素加载到该区域中呢?
它在替代品上的使用/好处的真实示例将会震撼!
区域允许您在程序中定义为特定目的而存在的位置。例如,您可能有一个菜单区域或页脚区域。然后,您可以将这些特定区域的视图/视图模型分离到它们自己的程序部分中。
因此,您将拥有用于 Menu 和 Footer 的单独 ViewModel,而您的 ApplicationViewModel 将只处理内容,而不是为and提供ApplicationViewModel
包含属性,并让 View 将每个部分绑定到这些属性。这是在应用程序中分隔一些逻辑边界的更好方法。MenuViewModel
FooterViewModel
就我个人而言,我认为区域被过度使用和滥用。我几乎从不使用它们,除非我有与我的应用程序代码的其余部分无关的页眉或页脚之类的东西。它们也主要用于 View-First 开发,我更喜欢 ViewModel-First。
将 RegionManager 与 EventAggregator 进行比较,您会看到它的优势......
EventAggregator 允许不同的组件发布/订阅事件,而无需相互耦合。RegionManager 也是如此……您可以将视图加载到区域中,而其他视图不知道那里发生了什么。它将您的视图彼此分离......这并不是说每个视图都应该不知道彼此......有时一个视图应该知道另一个视图。
查看 Microsoft Outlook(注意:我在这里编造一些东西,包括名称,因为 Outlook不是用 WPF 编写的,而是用 C++ 编写的):
主 UI 将具有以下区域:
区域是在标准控件上定义的(因此您仍然需要标准控件),更具体地说是 ItemsControl、ContentControl 和 Selector 开箱即用(您可以将其他控件扩展为“区域支持”)。它们允许另一段代码通过解析和加载适当的视图到这些区域来管理这些区域。基本上,保持事物解耦。
您是主 UI 不需要了解有关您的应用程序的所有信息;相反,它只需要知道它有一个菜单、导航、内容和侧边区域。实际放置在区域中的视图无关紧要。现在,这并不意味着每个视图都应该相互分离。我稍后再谈。
那么,它实际上是如何解耦的呢?这是一个场景:单击导航控件中的日历图标。那么当你这样做时会发生什么?
NavigationView
- 按钮(图标)绑定到一个ICommand
,所以它调用ExecuteLoadCalendar()
函数。NavigationViewModel
- 该ExecuteLoadCalendar()
函数使用EventAggregator
来宣布用户正在尝试启动日历。ContentController
-ContentController
已订阅LoadCalendarAggregateEvent
,因此已执行。在这里,它使用和区域名称解析/激活CalendarView
( COUPLED )。它应该通过抓取 a而不是 a 来做到这一点。IRegionManager
ICalendarView
CalendarView
在整个过程中,除了ContentController
和CalendarView
/之外,每个部分都是解耦的ICalendarView
。当然,你可以说NavigationView
/通过一个and 函数NavigationViewModel
知道/ CalendarView
。好吧,“有点”与“他们做”不同,因为代码隐藏和视图模型代码永远不应该引用实际的/对象。CalendarViewModel
ICommand
CalendarView
CalendarViewModel
此外,我们可以通过使执行通用化来删除“排序”。除了具有ExecuteLoadCalendar()
功能之外,它还可以具有LoadContent(NavigationItem item)
其中AggregateEvent
有效负载是某种标识的功能,例如,item.Name (String)
(从 DB、XML 等加载)以声明他们单击了“日历”。使用ContentController
相同的数据来解析“日历”而不是一个ICalendarView
(因为它不应该关心什么接口/类型被解析/激活ContentRegion
——它只需要一个对象来激活)。我使用 MEF,因此可以使用以下代码块来实现:
[Export("Calendar")]
public class CalendarView : UserControl, ICalendarView { }
那么,视图可以相互了解吗?是的!例如,我EmailUserControl
有一个搜索栏/电子邮件列表以及一个预览窗格。这两个控件可以是EmailListUserControl
,它由一个搜索栏和一个 ItemsControl 组成,还有一个EmailContentUserControl
,它只是所选电子邮件的预览窗格。它们必须是单独的控件吗?不,但如果它们是,那么我们可以EmailContentUserControl
在单独的窗口中打开电子邮件时重复使用。因此,这是一个EmailUserControl
与 2 个不同视图(theEmailListUserControl
和 the EmailContentUserControl
)耦合的示例。
为什么这与其他方法更好/不同:它将视图彼此分离(并防止视图模型需要了解视图)。
Region启用的场景
我浏览了这篇文章以获得答案: http: //www.developmentalmadness.com/archive/2009/10/14/mvvm-and-prism-101-ndash-part-3-regions.aspx
据我所知,区域功能旨在在既不是您的视图也不是您的视图模型的代码中启用视图注册/注入。
以一个ContentPresenter
控件为例。如果您使用它而不是区域,您的视图模型将必须返回具体视图,以保持主视图与其子视图无关。
如果您使用 aItemsControl
并将其绑定到视图模型上的任意数据,则需要在主视图的 DataTemplate 中指定要实例化哪些视图。
使用区域,您可以将视图注册到依赖注入容器中的区域。视图和相应的视图模型都不需要知道将在运行时使用的具体视图的任何信息。它将由容器注入。
这使您可以将主视图与其子视图的任何信息完全分离,而无需强制您的视图模型了解有关这些子视图的任何信息。
具体用例
这有多大用处,以及这将实现哪些具体场景,我不确定。我使用了ContentPresenter
带有插件架构的 a,但我不确定它是否适合这个模型。使用插件模型,您希望将视图和视图模型绑定在一起,因此这种方法对您没有任何好处。
我想如果你发现你有很大的不相关的观点并想把它们分开,那效果最好。通过一次只注入视图和视图模型的一部分,它可能有助于将您的集成测试相互隔离。
我正在为引人注目的现实世界用例抓住稻草:) 在几乎所有情况下,您都可以简单地使用 aUserControl
代替,并且可以放弃整个动态注册的事情,没有真正的缺点。