To build a composite application view in my application, with different regions, untill now, I've always used content presenter and used DataBinding to set its content.
If I wanted to change its content, I would just have to use an event aggregator, publish a ViewZoneChangedEvent, subscribe to it in the "shell" window, and update the viewmodel accordingly so that the new data would be available for the binding and the UI be updated.
Now, I recently came across those Regions in Prism, actually I had seen them for a while but I didn't feel comfortable with them, but since Prism is some kind "best practices guidance" maybe I'm missing something : Let me explain why I feel uncomfortable.
with my old way of doing, there is no coupling with the XAML. you never mention any specific magic string that should be present in the XAML, and I think that's essential, since the style can change.
If at least the regions would perform a compile-time check of the region names ( check it really exists somewhere ) that would enforce using valid region names and be very helpful when refactoring, but as far as I know, there's no such thing. Some people use enums and the ToString
method of an enum to convert it to a string and use it as a region name, but again, as far as I know, there's no real routine to check if the string typed really is valid and show an error when compiling the way it is done for Brushes.InValidColor for instance.
So, my question is the following : what do the prism regions bring to the table compared to plain old binding (plus eventAggregator if you wish to communicate across ViewModels) ?
and are my assumptions true about the compile-time verification of the region names ?
It's much cleaner to use regions than to do it "by hand". Using regions you don't require any knowledge on how you need to add new views to the composite parent. If you do it "by hand" you have to add some code-behind in your view, which is a bad thing.
The way I avoid magic strings is to define all the region names as constants
public class RegionNames
{
public static string MainRegion { get { return "MainRegion"; } }
}
and then set the region up as a resource thus (in the App.xaml for instance)
<Application.Resources>
<ResourceDictionary>
<infrastructure:RegionNames
xmlns:infrastructure="clr-namespace:MyClass.Silverlight;assembly=MyModule.Silverlight"
x:Key="RegionNames" />
</ResourceDictionary>
</Application.Resources>
I then add module-specific region names as constants at the module level.
There's unfortunately no compile-time check but it's much better and cleaner than adding the region names directly in the XAML, especially if you reuse the name in code later on.
EDIT: I forgot to include the XAML to show how you use this constant. This is now corrected.
Somewhere at the top of the XAML, include the reference to the region manager:
xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
And then when setting up the region use the region name defined as the resource
<ItemsControl Regions:RegionManager.RegionName="{Binding MainRegion, Source={StaticResource RegionNames}}" />