Compare the RegionManager to the EventAggregator and you'll see the advantage of it...
The EventAggregator allows different components to publish/subscribe to events without being coupled to each other. The same goes with the RegionManager... you can load a view into a region without your other view knowing what is going on in there. It decouples your views from each other... that's not to say EVERY view should be unaware of each other... there are times where a view should know about another view.
Look at Microsoft Outlook (note: I'm making things up here, including names, as Outlook is not written in WPF, but instead C++):
The main UI would have the following regions:
- MenuRegion
- NavigationRegion
- ContentRegion
- SideRegion
Regions are defined on standard controls (so you still need standard controls), more specifically ItemsControl, ContentControl, and Selector out of the box (you can extend other controls to be "region supportive"). They allow another section of code to manage the regions by resolving and loading the appropriate views into those regions. Basically, to keep things decoupled.
You're main UI does not need to know everything about your application; instead, it just simply needs to know that it has a Menu, Navigation, Content, and Side Region. Which views that actually are placed in the regions doesn't matter. Now, that doesn't mean every view should be decoupled from each other. I'll get to that later.
So, how does it actually decouple? Here's a scenario: click on the calendar icon in the Navigation control. So what should happen when you do that?
NavigationView
- The Button (Icon) is bound to an ICommand
, so it calls the ExecuteLoadCalendar()
function.
NavigationViewModel
- The ExecuteLoadCalendar()
function uses the EventAggregator
to announce that the user is attempting to launch the calendar.
ContentController
- The ContentController
had subscribed to the LoadCalendarAggregateEvent
, so that is executed. Here, it resolves/activates the CalendarView
(COUPLED) using the IRegionManager
and the region name. It should do this by grabbing an ICalendarView
instead of a CalendarView
.
Throughout the process each part is decoupled except for the ContentController
and the CalendarView
/ICalendarView
. Of course, you could say that the NavigationView
/NavigationViewModel
sort of knew about the CalendarView
/CalendarViewModel
by having an ICommand
and function. Well, "sort of" isn't the same as "they do", because the code-behind and view-model code should never reference the actual CalendarView
/CalendarViewModel
objects.
Also, we can remove the "sort of" by making the execute generic. Instead of having a ExecuteLoadCalendar()
function, it can have a LoadContent(NavigationItem item)
function where the AggregateEvent
payload is an identification of some sort, for example, item.Name (String)
(loaded in from a DB, XML, etc) to state they clicked "Calendar". The ContentController
uses the same data to resolve "Calendar" instead of an ICalendarView
(because really it shouldn't care what interface/type is resolved/activated in the ContentRegion
-- it just needs an Object to activate). I use MEF, so this can be achieved with the following code block:
[Export("Calendar")]
public class CalendarView : UserControl, ICalendarView { }
So, can views know about each other? Yes! For example, my EmailUserControl
has a search bar/list of emails as well as a preview pane. These 2 controls can be EmailListUserControl
, which is composed of a search bar and an ItemsControl, and a EmailContentUserControl
, which is just a preview pane for the selected email. Do they have to be separate controls? No, but if they are then we can reuse the EmailContentUserControl
when we open the email in a separate window. So, this is an example where the EmailUserControl
is coupled to 2 different views (the EmailListUserControl
and the EmailContentUserControl
).
Why is this better/different from other approaches: It decouples views from each other (and guard against view-models needing to know about views).
#region
. I was about to write an answer that said "absolutely no point - the compiler ignores them, and incompetent programmers use them instead of refactoring" – Orthorhombic#region
. – Midwinter