Region not respecting Grid Column assignment

Topics: Prism v4 - WPF 4
Oct 26, 2012 at 8:53 PM

I'm encountering an odd issue when trying to setup nested regions. In my Shell, I have a ContentControl marked as "ContractRegion". I can populate that region with my ContractView and its associated data without an issue.

Then, on the ContractView, on the left is a ListBox (shows data correctly) and on the right is another ContentControl defining a second region called "ProjectRegion". When I select a project from the ListBox, I call a method on my controller that get's the instance of the ProjectView and activates it inside ProjectRegion.

The problem is that the view loads on the entire window, not inside the Grid.Column that it's supposed to.

Here is some code:

My Shell.xaml:

<Window x:Class="EstimateModelRedesign.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cal="http://www.codeplex.com/CompositeWPF"
        xmlns:local="clr-namespace:EstimateModelRedesign"
        Title="Shell" Height="462" Width="523">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="11*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <ContentControl cal:RegionManager.RegionName="ContractRegion">
        </ContentControl>
        <Button Grid.Row="1" Content="START!" Command="{Binding Path=StartCommand}"/>
    </Grid>
</Window>

My ContractView.xaml:

<UserControl x:Class="EstimateModelRedesign.ContractView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:cal="http://www.codeplex.com/CompositeWPF"
             xmlns:local="clr-namespace:EstimateModelRedesign"
             mc:Ignorable="d" 
             d:DesignHeight="417" d:DesignWidth="502">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="350"/>
        </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding Path=Projects}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedProject}"/>
        <ContentControl Grid.Column="1" cal:RegionManager.RegionName="ProjectRegion"/>
    </Grid>
</UserControl>

And finally, my ProjectView.xaml:

<UserControl x:Class="EstimateModelRedesign.ProjectView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="{Binding Path=Name, StringFormat='Project Name: {0}'}" />
    </Grid>
</UserControl>

I activate views like this on my controller class:

public void SetupContract()
{
    IRegion region = _regionManager.Regions[RegionNames.ContractRegion];

    var contractView = region.GetView("ContractView");

    if (contractView == null)
    {
        contractView = ServiceLocator.Current.GetInstance<ContractView>();
        region.Add(contractView, "ContractView");
    }

    region.Activate(contractView);

    Contract test = new Contract("Contract 1", "0");

    for (int i = 0; i < 3; ++i)
    {
        Project proj = new Project(string.Format("Project{0}", i))
        {
            Quantity = i + 1,
            UnitCost = i * 10,
            UnitSellPrice = (i * 10) + 5
        };

        test.Projects.Add(proj);
    }

    _eventAggregator.GetEvent<ContractLoaded>().Publish(test);
}

public void ProjectSelected(Project project)
{
    IRegion region = _regionManager.Regions[RegionNames.ContractRegion];

    var projectView = region.GetView("ProjectView");

    if (project != null)
    {
        if (projectView == null)
        {
            projectView = ServiceLocator.Current.GetInstance<ProjectView>();
            region.Add(projectView, "ProjectView");
        }

        region.Activate(projectView);
        _eventAggregator.GetEvent<ProjectLoaded>().Publish(project);
    }
}

Oct 26, 2012 at 8:56 PM

I've added the sample I'm working on to my SkyDrive account

Oct 26, 2012 at 9:17 PM

I figured it out...I realized in the ProjectSelected method on the controller, I was grabbing the wrong region string from the RegionNames class. That's what I get for copy/paste!!

Developer
Oct 26, 2012 at 9:21 PM

Hi,

I haven't checked your repro sample application yet, but so far after reviewing the code snippets you posted, I found that in the ProjectSelected method you are injecting the ProjectView inside the ContractRegion instead of the ProjectRegion. This can be seen in the following line of the ProjectSelected method:

IRegion region = _regionManager.Regions[RegionNames.ContractRegion];

Hence, when the aforementioned method is executed, the ContractView is being "replaced" by the ProjectView.

Please let us know if using the ProjectRegion instead of the ContractRegion in your ProjectSelected method solves the issue you are mentioning.

Regards,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Oct 26, 2012 at 9:22 PM

Thanks Damian, I had just noticed that before you replied. Changed my code and everything works as expected now. Thanks for the reply.