Region defined in a view is not added to RegionManger.Regions collection

Topics: Prism v4 - WPF 4
Dec 5, 2010 at 4:07 PM
Edited Dec 5, 2010 at 6:24 PM

Hi,

I have a view defined in a module that defines a new region. When I navigate to this view or I add this view to the main region, the new region defined in that view is not added to the RegionManager.Regions collection. This is happening because I am using the MVVM pattern and I am not navigating to a view itself but I navigate to the ViewModel. I am using the DataTemplate approach defing in the RresourceDictionary the view to use when the ViewModel need to be shown (ViewModel First approach with DataTemplate).

I did a test and, instead of using the above approach, I navigated to the View defining the new region, changing the code behind to inject the ViewModel (ViewFirst approach) and in this case I got the new region being added to the Regions collection.

Is this by design, I mean it is not supported adding new regions when using the ViewModel First approach with DataTemplate?

Thanks

Antonio

Dec 6, 2010 at 8:22 PM

Hi Antonio,

The behavior you are describing is by design. Regions defined inside DataTemplates cannot be found by the DelayedRegionCreationBehavior behavior. You can find a more detailed explanation of this in the following thread.

You could, however, apply other of the possible alternatives for the ViewModel First approach.

I hope this information is useful.

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

Dec 7, 2010 at 9:04 AM

Hi Miguel,

so this means that I must move from the ViewModel First approach to the ViewFirst approach, as I read in the documentation that I can only use ViewModel first with DataTemplate if I want to use Prism Navigation feature, correct?

Thanks

Antonio

Dec 7, 2010 at 2:28 PM

Antonio,

If you need to have a region defined in a view that will be navigated to, you can still use the ViewModel First approach (that is, having the view as a dependency to the ViewModel), but when you perform the navigation, you should need to navigate into the view.

Other alternatives that would allow you to keep using the ViewModel First with DataTemplate approach would be to:

  • Create a Region Behavior that supports creating regions from inside DataTemplates. You can read more about this in Appendix E: Extending Prism
  • Use the IRegionCollection Add method (which can be found in the RegionManagerExtensions class) to add your IRegion directly to the RegionCollection of your RegionManager

Thanks,

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

Dec 8, 2010 at 7:36 AM
Edited Dec 8, 2010 at 9:06 AM

Miguel,

any hint/sample on how to create the Region Behavior to create regions from inside DataTemplate? I read the appendix but I only got how to implement and register the behavior, I don't have any idea on how to discover regions inside DataTemplate.

Thanks

Antonio

Dec 9, 2010 at 9:38 PM

Hi Antonio,

The behavior you need to create for regions inside DataTemplates to be discovered should be similar to the DelayedRegionCreationBehavior. This behavior "(...) creates a new IRegion when the control that will host the IRegion is added to the visual tree(...)". However, regions defined inside DataTemplates currently cannot be found by this behavior. A possible cause for this might be that the DataTemplates may not currently being added to the Visual Tree.

I hope this information is useful.

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

Developer
Dec 10, 2010 at 8:45 PM

Hi Antonio,

Here you can find a sample which exemplifies how to put regions inside Data Templates.

This application uses a content control with a region that is populated using view model first approach with a data-template for the view model type. Inside that data template, there is another content control with a region that is populated using the view model first approach and another data-template for the second view model type. Inside the sample you'll find further explanations.

Also, you might check if you're having an exception that you're not detecting in your code.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Dec 10, 2010 at 10:07 PM

Hi Guido,

Thanks for your sample.

I tried it and it works but when I tried changing it using the NavigationService it doesn't work anymore.

I changed the application in this way on the MainWindow code behind:

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    [Export]
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

		this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        [Import]
        public IRegionViewRegistry ViewRegistry { get; set; }

	[Import]
	public IRegionManager RegionManager { get; set; }

        [Import]
        public IRegionBehaviorFactory RegionBehaviorFactory { get; set; }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
			//this.ViewRegistry.RegisterViewWithRegion("MainRegion", () => new MainViewModel());
			//this.ViewRegistry.RegisterViewWithRegion("SubRegion", () => new SubViewModel()); 
			RegionManager.RequestNavigate("MainRegion", new Uri("MainViewModel", UriKind.Relative));
			RegionManager.RequestNavigate("SubRegion", new Uri("SubViewModel", UriKind.Relative));
        }
    }
}
and I exported the two viewmodels in this way:
   [Export("MainViewModel")]
    public class MainViewModel
    {
        public string Message
        {
            get
            {
                return "Hello from the MainViewModel.";
            }
        }
    }


    [Export("SubViewModel")]
    public class SubViewModel
    {
        public string Message
        {
            get
            {
                return "Hello from the SubViewModel.";
            }
        }
    }

Hope to have done it correctly, as I don't have experience with Mef.
Thanks
Antonio
Developer
Dec 13, 2010 at 4:58 PM

Hi Antonio,

When you navigate to a view or view model using a URI, the view is created through the use of MEF. In order for the SubViewModel to be exported correctly, you need to have added the assembly in which it is contained to the Aggregate Catalog. You could add something like this to the MainBootstrapper class to achieve what I'm saying:

 protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(MainBootstrapper).Assembly));
}

Additionally, due to a timing issue, when you call this line:

RegionManager.RequestNavigate("SubRegion", new Uri("SubViewModel", UriKind.Relative));

The SubRegion will not have been created yet. So you could replace that line by this one:

this.ViewRegistry.RegisterViewWithRegion("SubRegion", () => ServiceLocator.Current.GetInstance<SubViewModel>("SubViewModel"));

That way, the SubViewModel will be added to the SubRegion when the region is actually created.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Developer
Jan 18, 2011 at 4:35 PM

Hi Antonio,

You might also find the following work item useful to fulfill your requirement:

Region Registration Fails w/ Templated Controls

In that work item an alternative approach is proposed, which implies modifying the RegionManagerRegistrationBehavior's FindRegionManager method.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi