How RegionManager gets regions after setting RegionManager dependency property?

Topics: Prism v2 - Silverlight 2, Prism v2 - WPF 3.5
Mar 28, 2009 at 2:02 PM
I am in a debugging session trying to find out why my scoped RegionManager doesn't get the Regions I excpect.

I start a new (scoped) RegionManager when I add a view to the main region of the shell window:
IRegionManager layoutsMgr = region.Add(new DockLayout(), null, true);

The code for this new view is:

<UserControl x:Class="Jacobi.Application.Layouts.DockLayout"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
    xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock">
    <ContentControl>
        <ad:DockingManager >
            <ad:ResizingPanel Orientation="Vertical">
                <ad:DockablePane cal:RegionManager.RegionName="Top">
                </ad:DockablePane>
               
                <ad:ResizingPanel Orientation="Horizontal">
                    <ad:DockablePane cal:RegionManager.RegionName="Left" >
                    </ad:DockablePane>

                    <ad:DocumentPane cal:RegionManager.RegionName="Center">
                    </ad:DocumentPane>
                   
                    <ad:DockablePane cal:RegionManager.RegionName="Right" >
                    </ad:DockablePane>
                </ad:ResizingPanel>

                <ad:DockablePane cal:RegionManager.RegionName="Bottom" >
                </ad:DockablePane>
            </ad:ResizingPanel>
        </ad:DockingManager>
    </ContentControl>
</UserControl>

After the view is added I can only see the "Center" region on the scoped RegionManager. Question is why?

When debugging I can see the static RegionManager.CreateRegion method fire 5 times (callback on dependency property), once for each region. That seems to work fine.
I can also see the scopedRegionManager being set on the RegionManager dependency property on the DockLayout control. When that call returns it contains only the center region. I have not found yet how a region is wired up to the region manager in CAL.

When I change the view to:

<StackPanel>
        <ContentControl cal:RegionManager.RegionName="Top"/>
        <ContentControl cal:RegionManager.RegionName="Left"/>
        <ContentControl cal:RegionManager.RegionName="Center"/>
        <ContentControl cal:RegionManager.RegionName="Right"/>
        <ContentControl cal:RegionManager.RegionName="Bottom"/>
</StackPanel>

or make it a little more complex like:

<ContentControl>
    <StackPanel>
        <ContentControl cal:RegionManager.RegionName="Top"/>
        <Grid>
            <ContentControl cal:RegionManager.RegionName="Left"/>
            <ContentControl cal:RegionManager.RegionName="Center"/>
            <ContentControl cal:RegionManager.RegionName="Right"/>
        </Grid>
        <ContentControl cal:RegionManager.RegionName="Bottom"/>
    </StackPanel>
 </ContentControl>

It works fine. I get 5 regions in my scoped RegionManager.
So there is something in the AvalonDock types that breaks the discovery of regions.

What happens when the RegionManager dependency property is set?
I hope that the answer to this question will bring me closer to solving the problem.

BTW: AvalonDock is available here on codeplex.

Apr 8, 2009 at 7:14 AM
Can someone of the team please help me!

Entering the RegionManager.SetRegionManager method the RegionManager has no regions in its collection.
http://www.xs4all.nl/~mjacobi/Temp/CompositeWPF_SetRegionManager1.JPG
After the dependency property has been set on the target, the regions are filled on the RegionManager!? 
http://www.xs4all.nl/~mjacobi/Temp/CompositeWPF_SetRegionManager2.JPG
My breakpoint in the Add method of the RegionCollection is not hit!?

So what happens when the RegionManager dependency property is set on a DependencyObject target?

Thanx,
Marc
Apr 8, 2009 at 4:43 PM
Edited Apr 8, 2009 at 5:21 PM

Hi,

Whenever you try to access the Regions property on the region manager, this will raise an event that will make every created region try to register istself in a region manager if it wasn't already (that's why debugging and trying to see the internal state of the RegionManager might not be the same as accesing the "Regions" property).

You can raise this event explicitly by calling the static method RegionManager.UpdateRegions() to see if this helps you.

How does this "try to register istself in a region manager" works?
The RegionManagerRegistrationBehavior class will traverse the visual tree of the target control (in your case a DockablePane) and try to get the value of the RegionManager attached property. If the value is null, it will check its parents value, and so on. As long as the DockablePanes are logical descendants of the UserControl (which is the one that has the scoped region manager assigned value), everything should work fine.
Nevertheless I've seen strange behaviors with DockManagers, as they are not usually logical parent of their contents. You could workaround this by explicitly setting the RegionManager attached property on the DockablePane to the View's RegionManager:

<UserControl x:Class="Jacobi.Application.Layouts.DockLayout"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
    xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
    x:Name="View">
    <ContentControl>
        <ad:DockingManager >
            <ad:ResizingPanel Orientation="Vertical">
                <ad:DockablePane cal:RegionManager.RegionName="Top" cal:RegionManager.RegionManager="{Binding Path=(cal:RegionManager.RegionManager) ElementName=View}">
                </ad:DockablePane>
               
                <ad:ResizingPanel Orientation="Horizontal">
                    <ad:DockablePane cal:RegionManager.RegionName="Left" ---same here--->
                    </ad:DockablePane>

                    <ad:DocumentPane cal:RegionManager.RegionName="Center"---same here--->
                    </ad:DocumentPane>
                   
                    <ad:DockablePane cal:RegionManager.RegionName="Right" ---same here--->
                    </ad:DockablePane>
                </ad:ResizingPanel>

                <ad:DockablePane cal:RegionManager.RegionName="Bottom" ---same here--->
                </ad:DockablePane>
            </ad:ResizingPanel>
        </ad:DockingManager>
    </ContentControl>
</UserControl>

In the example below, you could use ElementName, or RelativeSource finding the UserControl ancestor so you don't need to assign the x:Name property on the UserControl...

Let me know if this helps,
Julian Dominguez
http://blogs.southworks.net/jdominguez

Apr 10, 2009 at 1:11 PM
Hi Julian,

Unfortunatly naming the root didn't help:

cal

 

:RegionManager.RegionManager="{Binding Path=cal:RegionManager.RegionManager, ElementName=View}"

 

(It's a little different than the sample you gave, but I think yours had errors ;-)
I don't think I'm going to persue this any further. Its just takes up too much time. I will try to find another docking control or skip that altogehter.

Thanx for your anwser anyway.
Apr 13, 2009 at 6:19 PM
Hi
I'm sorry to hear that.
By the way, I believe that the correct syntax is 

cal:RegionManager.RegionManager="{Binding Path=(cal:RegionManager.RegionManager), ElementName=View}"

Notice the parenthesis. This is because you are binding to an attached property of the target element. I was missing a comma in the previous example (this is because I'm doing this directly in Codeplex rather than VS, which is how I'm supposed to :P)

I hope you can solve this without further issues.
Julian


Apr 14, 2009 at 7:27 AM
Edited Apr 14, 2009 at 7:40 AM
Nope, that didn't make any difference. Still no regions in the RegionManager (after property access).