Windows Phone 7 Developer Launch - Learn More
kick it on DotNetKicks.com   Shout it  

MVVM with Prism 101 – Part 3: Regions

Source Code

This is the third post in a series of articles about implementing the Model-View-View-Model (MVVM) architectural pattern for Silverlight/WPF. The bulk of the series describes the implementation details when using the Composite Application Library (Prism) Framework. For some background on MVVM as well as a discussion on the Bootstrapper concept see part 1. For more about the Shell concept I’ll be referencing in this article, see part 2.

Regions

Within the Prism Framework, Regions are analogous to the ContentPlaceHolder control used in an ASP.NET MasterPage. However a Region is not a control, it is applied to a control via the RegionName attached property – like this:

<ContentControl Regions:RegionManager.RegionName="Region1" />

I wanted to provide a graphic here, but since I lack any artistic talent and my skills with Visio are similarly stunted I have “borrowed” a graphic from the Prism documentation and hope they don’t mind:

UICompDCFig2-Layout

As demonstrated in this image, the shell has a number (in this case 2) of regions defined which indicate areas of the UI where a view may appear. Each region is explicitly named and generally defines the type of content which will appear in the region. This allows the layout of the UI to evolve over time while each view is unaffected because it is isolated from the details where it appears on the surface.

Regions can be applied to any control which inherits from ContentControl, ItemsControl or Selector and in the case of Silverlight there is additionally explicit support for the Tab control since it doesn’t inherit from ItemsControl like it does in WPF. Depending upon the control you use to define your region the views hosted within will behave differently. For example, the ContentControl will only display one view at a time - whichever is the active view. This allows you to create a navigation view (like above) using a Selector. The SelectedItem can be used to determine which view is hosted within the ContentControl. Or another option providing similar results could be to use a Tab control instead. The tabs will provide your navigation and the active tab will determine which view to display without any coding on your part.

If you wanted to display multiple instances of the same (or similar) views at the same time you could take advantage of an ItemsControl, like you would use a DataTemplate, except that each view can have its own View-Model.

Now that we understand what a region is I want to look at how to use them. The whole point of regions is to host views and a view can be any Object. There is no requirement that the view implement any interfaces or abstract classes, but I would recommend sticking to classes which inherit from DependencyObject. That said, there are two methods used to add your view object to a region: View Discovery and View Injection.

View Discovery

View Discovery is a passive means of adding a view. You simply register either the view’s type or a delegate which returns your view with the RegionManager which can be obtained via Dependency Injection or directly from your IoC container after Bootstrapper has run. When your views are mostly static or you have a default view which will to be displayed when your Shell loads then this is often the method you will use to load your views.

By type:

IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MainRegion", typeof(MyView));

Or using a delegate:

IRegionManager regionManager = Container.Resolve<IRegionManager>();
regionManager.RegisterViewWithRegion("MainRegion", () => Container.Resolve<IMyView>());

By default, your view will be displayed auto-magically once your region is created. View Discovery works well with a Tab control for navigation and because with Xaml you can do almost anything you like with the UI your Tab control doesn’t have to look like tabs. The Reference Implementation (RI) in the Prism Framework samples uses a tab control for navigation – it looks nice and doesn’t look at all like tabs. If you don’t require much control for your navigation then stick with View Discovery as your method. This is the method you’ll see used throughout this series in the source code and code snippets.

View Injection

View Injection gives you more control by allowing you to programmatically add/remove and activate the views in a region. This technique can be valuable for master/detail scenarios as well as for navigation controls. 

   1: string viewName = employeeId.ToString(CultureInfo.InvariantCulture);
   2: IRegion detailsRegion = regionManager.Regions["DetailsRegion"];
   3: object view = detailsRegion.GetView(viewName);
   4:  
   5: if(view == null)
   6: {
   7:     view = Container.Resolve<IEmployeeView>();
   8:     detailsRegion.Add(view, viewName);
   9: }
  10:  
  11: detailsRegion.Activate(view);

In the above snippet, assuming you already have references to your IoC container (line 7) and IRegionManager instance (line 2) then you’ll need to resolve references to your view (line 3 or 7) and the region where you’ll be injecting the view (line 3). Then after you add the view to the region (line 3) you activate the view.

The Controller Pattern

If you plan on using View Injection then I would recommend looking at the Controller pattern as a way of managing the views in the targeted region. There is a View Injection Quick Start included with the Prism Framework samples and source code which would be a valuable guide to doing this right. Otherwise, if you don’t mind waiting until my next post, I’ll go into a bit of a breakout on the Controller pattern and how it is used with View Injection.

Conclusion

We’re getting closer to the meat of this series where we’ll be getting into topics where we can finally do something besides print “Hello World” messages that are hard-coded into our Xaml. My next post will be a breakout on the Controller pattern and View Injection before I move on to Modules.

Source Code

tags: , , ,

kick it on DotNetKicks.com   Shout it  

Feedback

# re: MVVM with Prism 101 – Part 3: Regions

Gravatar Nice article Mark!

How would you handle the situation where you're showing a Window (for adding and updating items) based on some actions. Would you create a separate region for this Window?

Thanks,

Mark Monster 10/21/2009 7:37 AM | Mark Monster

# re: MVVM with Prism 101 – Part 3: Regions

Gravatar Thanks, Mark.

Sure, add a popup control to your view, then add a region and depending on your needs you can either use View Discovery where the IsOpen property of your popup control is bound to a bool property on your ViewModel (I'll be posting on ViewModel soon). Bind a command to your button (or whatever will trigger your user action) and then use that command to set the bool property on your ViewModel to true.

If you're going to use View Injection instead of View Discovery then check out my following post www.developmentalmadness.com/.../...ction-and.aspx on managing View Injection.

That should take care of it.
10/21/2009 1:03 PM | MarkJMiller

# re: MVVM with Prism 101 – Part 3: Regions

Gravatar I Like your articles the way u explains. I have really confused with the Attached Behavior properties in Silverlight and how it works with prism.
Is there any properties for selectionchanged others.

Thanks
Lavanya
11/1/2009 10:37 AM | lavanya

# re: MVVM with Prism 101 – Part 3: Regions

Gravatar Lavanya, if you're trying to hook into selection changed event there is no attached property for prism which will execute a command when selection changed fires. The only event that comes with a hook for Prism is "Click". Prism has support to allow you to add support for additional events, but typically what I do is have a SelectedItem property on my View-Model that I bind to my list control using two-way binding. This always provides what I need w/o having to write a custom attached behavior. 11/2/2009 1:59 PM | MarkJMiller

# re: MVVM with Prism 101 – Part 3: Regions

Gravatar An interesting observation is that the region abstraction accepts objects, not necessarily DependencyObjects or UserControls. This implies that we can Add instances of View Models to regions, as long as we register the correct data template with the shell. All the DataTemplate contains is the appropriate View to use to display the VM.

One approach to this is to implement a service that the bootstrapper registers. The service can register VM to View mappings using code behind. (An example of this can be seen on my blog: http://szymonrozga.net/blog/?p=235). Whenever a module initializes, it can register the necessary mappings for its View Models. After that, adding VM instances into regions will render the VMs as the correct View.

This is a good approach as long as your View does not hold any state. ContentControl will recycle an instance of result of DataTemplate.LoadContent method and if your View contains state from a VM when switching to a different instance, strange behavior might follow. 3/11/2010 8:38 PM | Szymon Rozga

Comments have been closed on this topic.
 

 

Copyright © Mark J. Miller