Create Shell with MainRegion

Topics: Prism v4 - WPF 4
Sep 14, 2010 at 11:50 AM

Hi all. I want to create shell window with a one main region wich described and loaded from the other module. As usual simple tab control on the window and some control on the region.

I create Shell window with MainRegion and UserConrol with region for my prism module. But module doesn't load into region. Only clear window! Here's the code:

    public class ShedulerClientBootstrapper : UnityBootstrapper
    {
        protected override void ConfigureContainer()
        {
            Container.RegisterType<IShellViewModel, ShellViewModel>();
            Container.RegisterType<IShell, Shell>();
            Container.RegisterType<IMainViewModel, MainViewModel>();
            Container.RegisterType<IMainView, MainView>();
            base.ConfigureContainer();
        }
        protected override DependencyObject CreateShell()
        {
            IRegionManager regionManager = this.Container.Resolve<IRegionManager>();
            IShell shellwindow= Container.Resolve<IShellViewModel>().View;
            System.Type shelltype= shellwindow.GetType();
            regionManager.RegisterViewWithRegion("MainRegion", shelltype);
            regionManager.RegisterViewWithRegion("ClientGridView", () => Container.Resolve<IMainViewModel>().View);
            shellwindow.ShowShell();
            return shellwindow as DependencyObject;
        }
    }

    public interface IShell
    {
        IShellViewModel Model { get; set; }
        void ShowShell();
    }

    public interface IShellViewModel
    {
        IShell View { get; }
    }

    public partial class Shell : Window, IShell
    {
        public Shell()
        {
            InitializeComponent();
        }

        public void ShowShell()
        {
            this.Show();
        }

        public IShellViewModel Model
        {
            get
            {
                return DataContext as IShellViewModel;
            }
            set
            {
                DataContext = value;
            }
        }
    }

    public class ShellViewModel : IShellViewModel
    {
        public IShell View { get; set; }
        private IEventAggregator eventAggregator;
        private IUnityContainer container;

        public ShellViewModel(IShell view, IEventAggregator eventAggregator, IUnityContainer container)
        {
            View = view;
            View.Model = this;
            this.eventAggregator = eventAggregator;
            this.container = container;
        }
    }

<Window x:Class="ShedulerClient.Shell"
        <Grid>
            <ContentControl
                rgn:RegionManager.RegionName="MainView"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch"
                VerticalContentAlignment="Stretch" />
        </Grid>
    </StackPanel>
</Window>

MainView is the same. Differs only UserControl instead of Window class and ClientGridView region instead MainView.

If remove MainView and put the ClientGridView into ShellWindow an error occurs: Message = "An exception occurred while creating a region with name 'ClientGridView'. The exception was: System.InvalidOperationException: Window must be the root of the tree. Cannot add Window as a child of Visual.\r\n at System.Windows.Window.OnAncestor

Sep 17, 2010 at 4:22 PM

such a simple question...seems

Sep 17, 2010 at 4:24 PM

Hi,

This could be because, you are trying to add a Window as a child of another control, which is not allowed, as explained in this article"Window is a root element and, therefore, cannot be part of another element's content.".

You should check your entire code base to verify that there is no scenario where this is taking place, such as having a view inherit from Window.

Please let me know if this helps.

Fernando Antivero 
http://blogs.southworks.net/fantivero

Sep 21, 2010 at 7:08 AM
Edited Sep 21, 2010 at 7:10 AM

I don't see where in my code I'm trying to add a Window as a child of another control. Scheme is approximately as follows: UnityBootstrapper -> Shell (Window) -> MainView(UserControl).
But I rewrote some interfaces and it works only as at StockTrader RI:

        protected override void ConfigureContainer()
        {
            Container.RegisterType<IShell, Shell>();
            base.ConfigureContainer();
        }

        protected override DependencyObject CreateShell()
        {
            ShellPresenter presenter = Container.Resolve<ShellPresenter>();
            IShell view = presenter.View;
            view.ShowShell();
            return view as DependencyObject;
        }

    public interface IShellPresenter
    {
        IShell View { get; }
    }
    public interface IShell
    {
        void ShowShell();
    }
    public class ShellPresenter : IShellPresenter
    {
        public IShell View { get; set; }

        public ShellPresenter(IShell view) 
        {
            View = view;
        }
    }
    public partial class Shell : Window, IShell
    {
        public Shell()
        {
            InitializeComponent();
        }

        public void ShowShell()
        {
            this.Show();
        }
    }

Disappointing, but okay. The question then arises - is it possible to put regions into a region and to use main ViewModel in module to derived ViewModels for UserControls? i.e.:
If I have View with many custom UserControls I should to create ViewModels for each of them and to derive their from "base ViewModel" or use a one ViewModel for all Controls?

Sep 21, 2010 at 5:04 PM
Edited Sep 21, 2010 at 5:12 PM

Hi,

Nice to see that you solved the issue in your application. Please take into account that the approach implemented in the StockTrader RI is one of the recommended by the product team. But you should be able to extend or implement your own scenario.

Regarding to your question, it depends on your particular scenario. Therefore, if you need one ViewModel for each view (it is the common approach) , you could implement this. But if you need to use an only one ViewModel shared for all the views in a particular region, it is another possible approach.

If you need guidance on how to implement a MVVM advanced scenario, you could download the latest drop of prism and take a look at the MVVM Quickstart. Additionally, you could take a look at the documentation section in the CHM: MVVM Quickstart (new).

I hope this helps,

Fernando Antivero 
http://blogs.southworks.net/fantivero