Setting RegionName with Style Setters

Topics: Prism v2 - Silverlight 2
Jun 12, 2009 at 7:47 PM
Edited Jun 12, 2009 at 7:48 PM

I have been using the Setter elements within Styles to set the RegionName property for my ContentControls.

    <Style x:Key="CsaNavigationStyle" TargetType="CsaShell:NavigationContainer">
        <Setter Property="Regions:RegionManager.RegionName" Value="NavigationRegion" />
    </Style>

Doing this, I've been using the following syntax for adding my views to the regions

_regionManager.RegisterViewWithRegion(RegionNames.LoginPopupRegion, () => _container.Resolve<ILoginViewModel>().View);

Now I'm facing a problem.  When I try to look at my _regionManager.Regions collection, there are no regions.  Is there a reason why when regions are defined in this manner that they do not show up in the regions collection?

Jun 12, 2009 at 8:47 PM

Hi ethicalone,

 

I reproduced your scenario but I was not able to find the issue you mentioned. Below I wrote the steps I did to reproduce the scenario so that you can compare.

Below you can find some questions that might help us reproduce and solve the problem:

1.       How are you setting the style to the ContentControl?

2.       Is the CsaShell:NavigationContainer a special container? Is it using a special adapter?

3.       In your scenario, if you set the RegionManager.RegionName property directly in the ContenControl (not using styles), does the _regionManager.Regions contain items?

4.       Were (at what time of the execution) are you trying to retrieve the Regions Collection? (Remember that regions are attached to ContentControls when the control is loaded, not when the XAML property is set)

5.       Any additional information that you believe might be relevant

 

Repro Scenario

1.       I started with the HelloWorld  Quickstart that is included in Prism-v2 (Silverlight only solution)

2.       In the Shell.xaml file I changed the code as follows (declare the style and use it in the contentControl):

<UserControl x:Class="HelloWorld.Shell"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"

             Width="400" Height="300">

  <UserControl.Resources>

    <Style x:Key="CsaNavigationStyle" TargetType="ContentControl">

      <Setter Property="Regions:RegionManager.RegionName" Value="MainRegion" />

    </Style>

  </UserControl.Resources>

 

  <ContentControl Name="MainRegion" Style="{StaticResource CsaNavigationStyle}" />

</UserControl>

3.       In the Initialize method of the HelloWorldModule class I added the following code (test Regions collection):

 

public void Initialize()

{

    Debug.Assert(regionManager.Regions.Count() > 0);  // NOTE: Add using System.Linq;

    var mainRegion = regionManager.Regions["MainRegion"];

    Debug.Assert(mainRegion != null);

 

    regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));

}

 

 

Hope it helps!

 

Matias Bonaventura

http://blogs.southworks.net/matiasb

Jun 12, 2009 at 9:33 PM
Edited Jun 12, 2009 at 9:57 PM

Thanks for the quick reply.  I need to expand the repro since it seems that I've omitted a feature, Templates.  I've updated the example that you sent me for the HelloWorld.Shell

<UserControl x:Class="HelloWorld.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
             Width="400" Height="300">
    <UserControl.Resources>
        <Style x:Key="CsaMainRegionStyle" TargetType="ContentControl">
            <Setter Property="Regions:RegionManager.RegionName" Value="MainRegion" />
        </Style>
        <Style x:Key="CsaTemplatedRegionStyle" TargetType="ContentControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <ContentControl Name="MainRegion" Style="{StaticResource CsaMainRegionStyle}" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <ContentControl Name="CsaTemplatedRegion" Style="{ StaticResource CsaTemplatedRegionStyle }" />
</UserControl>

I'm using the Template property of the ContentControl to style my rather plain shell and allow end users to define their own look and feel around the regions within the ControlTemplate. With this code, I am getting the error I metioned in the first post.

Thanks again for the quick reply,

Rick

UPDATED:

Fixed an error in the code. That's what you get when you post before compiling :D

Jun 15, 2009 at 6:14 PM

Looking into this, it seems that the WeakReference events are not firing when UpdateRegion() is called within Prism.

Jun 18, 2009 at 3:38 PM

Matias, have you have an opportunity to look into this any futher?
Thanks
Rick

Jun 19, 2009 at 5:56 PM

Sorry for the delay... I've been in a rush this week.

 

You are right, the problem your are having is because of the templates. I'll try to explain what is going on:

1.       Regions are not attached to ContentControls when the RegionManager.RegionName XAML property is set. Instead they are attached when the control is loaded or when the RegionManager.UpdateRegions() method is called. (this is done by the DelayedRegionCreationBehavior class in prism and in the UnityBootstrapper class).

2.       Though regions are attached as explained before, they are not registered in the regionManager at that moment. Regions are registered in the RegionManger by the RegionManagerRegistrationBehavior which depends on the RegionManagerProperty dependency property to be set in one of the control's parent.

3.       This property is set in the bootstrapper to the shell (line 107 of the bootstrapper).

4.       As the control you are trying to set the regionManager is inside a template, it does not have a Parent, so the RegionManagerRegistrationBehavior.FindRegionManager method fails in finding  the correct RegionManager

 

 

Workaround

The only workarround I can think of is the obvious one: Do use the Styles for setting all of the look and feel properties, but set the region name in the control instead of in the styles. Another approach might be creating a custom RegionBeheavior with the same behavior than the RegionManagerRegistrationBehavior but with a customizaed FindRegionManager method that can find the RegionManager inside the template.

 

Hope it helps!

 

Matias Bonaventura

http://blogs.southworks.net/matiasb