"LocalRegionManager" and NonShared views

Topics: Prism v4 - WPF 4
Nov 5, 2012 at 8:50 AM
Edited Nov 5, 2012 at 8:53 AM

Hi there,

I am working on a WPF Prism application. In certain secondary windows, I need to create a different menu (not the one of the Shell).

The menu of the dependent window should compose according to the modules that are found and dynamically loaded.

The dependent menu views are singletons (CreationPolicy.Shared). Differently, the part creation policy of the dependent window has been set to NonShared, however an instance of the viewModel of this dependent window is kept alive as it is also used by another feature of the application (in other words, two views share the same viewModel)

The first time, in order to create the dependent window I do something like:

IRegionManager windowRegionManager = new RegionManager();
IWindow window = this.ServiceLocator.GetInstance<IWindow>();
RegionManager.SetRegionManager(window as DependencyObject, windowRegionManager);
viewModel viewModel = new viewModel(windowRegionManager, _serviceLocator)
                      {
                         Title = "Hello World!"
                      };
this._shellWindowViewModel.DependentViewModels.Add(viewModel);
window.ViewModel = viewModel;
window.Show();

After closing it, when I want to display again the same window, I simply create a new View (window) instance and I set the same ViewModel. Something like:

IWindow window = this.ServiceLocator.GetInstance<IWindow>();
var windowRegionManager = viewModel.LocalRegionManager;
RegionManager.SetRegionManager(window as DependencyObject, windowRegionManager);
window.ViewModel = viewModel;
window.Show();

Unfortunately, the result is not as expected. I guess something is wrong and not working at all, as I don't see the view that was previously registered in the dedicated and composable menu Region, though I use the same RegionManager for the new window instance.

Do you have any idea of what can cause the issue that I am facing? 

Thanks in advance,

Gianluca.

PS: Some further info: If I check the content of the LocalRegionManager, the one that I attach to the dependent window, I can see it hosts the dependent MenuView. 

Developer
Nov 5, 2012 at 6:26 PM

Hi,

Based on my understanding, the problem you are experiencing could be related to the fact that each Window instance has its own different regions.

Basically, when you create the Window for the first time, its regions will be registered in the RegionManager you set for that Window. For example, if the Window has a "WindowRegion," it will be registered in that RegionManager. However, the second time you create a Window you will have the previous RegionManager with its regions and the new Window with its own regions. That is, the "WindowRegion" of the second Window will NOT be "WindowRegion" of the RegionManager. Therefore, although the RegionManager is keeping its regions (and the regions are keeping their views), those are not the regions of the new Window, and the views are not being shown in them.

A possible approach to achieve the functionality you are mentioning could be to work with the content element of the Window. For example, instead of setting the RegionManager in the Window, you could set it in the Content element of the Window. Then, you could store the content of the first Window, and when creating the second Window you can change its Content property to hold the contents of the original Window. Like this, each Window you create will use the same UIElements, RegionManager and regions:

The first time:

IRegionManager windowRegionManager = new RegionManager();
IWindow window = this.ServiceLocator.GetInstance<IWindow>();

// We save the content of the window and set the RegionManager in it.
this.windowContent = window.Content as DependencyObject;
RegionManager.SetRegionManager(windowContent, windowRegionManager);

viewModel viewModel = new viewModel(windowRegionManager, _serviceLocator)
{
    Title = "Hello World!"
};
this._shellWindowViewModel.DependentViewModels.Add(viewModel);
window.ViewModel = viewModel;
window.Show();

 

And after the first time:

IWindow window = this.ServiceLocator.GetInstance<IWindow>();
            
// We no longer need to set the RegionManager again, as the content already has it.
//var windowRegionManager = viewModel.LocalRegionManager;
//RegionManager.SetRegionManager(window as DependencyObject, windowRegionManager);

window.Content = this.windowContent;

window.ViewModel = viewModel;
window.Show();

Take into account that you will need to remove the content from the previous Window before being able to set it as the content of the next Window. A simple method to do this could be to set the Content property of the Window to null in its Closed event.

I hope you find this useful,

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