How to create multi-shells use PRISM

Topics: Prism v4 - Silverlight 4
Apr 26, 2011 at 4:21 AM
Edited Apr 26, 2011 at 4:21 AM

Hi,

I developing a silverlight app, I have trouble when I want create multi-shells, use can change shell when they want.

How can I do this.

Thank you

Apr 26, 2011 at 4:29 AM

Hi,

The shell is nothing but the main silverlight app that gets loaded when your application is accessed. As far as I know you cannot load multiple shell applications on startup. What is the exact nature of your requirement? What do you mean by user can change the shell?

Cheers,

Ganesh

Apr 26, 2011 at 8:04 AM

Actually, use don't know shell :).

I mean when user run application they can change layout display (example: Shell_1 has 4 regions, they can change to Shell_2 has 3 regions,... and I will manipulate which views will display in these regions)

I know that CreateShell of Bootstrapper run only one time when app loaded, so I have no way to create another shell.

Thank you.

Apr 26, 2011 at 8:11 AM

In that case use this structure.

MainPage

  • MainRegion
    • Shell1.xaml (4 regions)
    • Shell2.xaml (3 regions)

When app loads, load Shell1 in MainRegion,or Shell2 whichever is default in your case. Now when changes layout (assuming from a drop down) to Shell2, load Shell2 in MainRegion. Here the concept of nested regions arise

Case 1

MainRegion (with Shell1)

  • SubRegion1
  • SubRegion2
  • SubRegion3
  • SubRegion4

Case 2

MainRegion (with Shell2)

  • SubRegion1
  • SubRegion2
  • SubRegion3

With this you can easily achieve what you want to.

Note MainPage.xaml, Shell1.xaml and Shell2.xaml are in your Shell project. And in the CreateShell you would do

protected override DependencyObject CreateShell()
        {
            return Container.GetExportedValue<MainPage>();
        }

 

Hope this helps.

Cheers

Apr 26, 2011 at 8:25 AM
Edited Apr 26, 2011 at 8:32 AM

Thank for quick response

I understand you ideal, the problem is I don't know have to implement it.

I tried create a MainPage with a Region is "ShellRegion", but I don't know how can I load Shell1 or Shell2 onto that (Shell1 and Shell2 have another Region and other views will use region of Shell1 or Shell2).

I'm using PRISM not MEF so I can not use function Container.GetExportedValue();

If quickly, can you create a simple example. I'm very appreciate.

Thank you.

Apr 26, 2011 at 8:28 AM

Unfortunately I cannot post code from work. If you can wait till end of today I can probably put something up for you.

Apr 26, 2011 at 8:47 AM

Sure, thank for your help.

Apr 26, 2011 at 5:33 PM

Here is the sample app. The app is structured as follows.

MainPage (MainRegion, has 2 buttons to switch between shells, Shell1 is loaded by default)

  • Shell1 (2 regions : Shell11Region and Shell12Region)
    • Shell1SubView1 loaded into Shell11Region
    • Shell1SubView2 loaded into Shell12Region
  • Shell2 (1 region : Shell2Region)
    • Shell2SubView1 loaded into Shell2Region

Hope this clears your understanding.

Cheers,

Ganesh

Apr 27, 2011 at 3:37 AM

Thank you very much.

I saw you're using MefBootstrapper, I'm using UnityBootstrapper, so can I ask a questtion

What difference between MefBootstrapper and UnityBootstrapper? Can I use UnityBootstrapper?

 

 

Apr 27, 2011 at 4:07 AM
Edited Apr 27, 2011 at 4:09 AM
Of course you can. So what you would do is register the views you want to navigate to in the unitycontainer like below
_unityContainer.RegisterType<Object, Shell1>("NestedRegions.Shell1.Shell1");

and you would navigate to it this way :

_regionManager.RequestNavigate("MainRegion", new Uri("NestedRegions.Shell1.Shell1", UriKind.Relative));

Using MEF or Unity is purely a matter of choice. I'm more comfortable with MEF so used that in the example. Both work the same, the difference being the views are resolved from UnityContainer if you use Unity or from AggregateCatalog if you use MEF.

For more information read up Basic region navigation (page 119) in the developers guide pdf.

Apr 27, 2011 at 7:30 AM

I have a bootstrapper like below

  protected override DependencyObject CreateShell()
        {
            //create shell window
            return Container.Resolve<MainPage>();
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            var catalog = new ModuleCatalog();
            catalog.AddModule(typeof(ContentModule));
            catalog.AddModule(typeof(TopModule));
            catalog.AddModule(typeof(LeftModule));
            catalog.AddModule(typeof(RightModule));
            catalog.AddModule(typeof(BottomModule));
            return catalog;
        }

And MainPage i register a Shell1 (or Shell2)

 public partial class MainPage: UserControl
    {
        private readonly IUnityContainer container;
        private readonly IRegionManager regionManager;

        public MainPage(IUnityContainer container,IRegionManager regionManager)
        {
            InitializeComponent();
            this.container = container;
            this.regionManager = regionManager;
            Loaded += MainPageLoaded;
        }

        void MainPageLoaded(object sender, System.Windows.RoutedEventArgs e)
        {
            var shell1 = container.Resolve<Shell1>();
            try
            {
                var region = regionManager.Regions["ShellRegion"];
                region.Add(shell1, null);
                region.Activate(shell1);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
    }

First I want to try load Shell1 to MainPage and Shell1 will load Top Views, RightViews, ......

But I'm not success, I don't know If MainPage load Shell1 and Shell1 load views or not.

Apr 27, 2011 at 7:56 AM

As far as I understand Shell1 seems to load modules into regions in it? If that is the case is Shell1 downloading the modules using modulemanager? For starters add a textblock in Shell1 that says something like "Shell1" so you know if Shell1 is loaded in the MainPage. You can use my app as a reference. If you're still having trouble upload your sample app and i'll have a look tonight !!

Apr 27, 2011 at 8:27 AM
Edited Apr 27, 2011 at 8:28 AM

Thank you

Here is my project, I got exception at OnChangeShellHandler

 

Tell me, if you can not get project or project can not built.

Apr 27, 2011 at 9:13 AM

Currently, I have switch between 2 shell. I change OnChangeShellHadler like below

But, I have a trouble. function OnChangeShellHandler call many time and it increase after I click button switch shell

  public void OnChangeShellHandler(string param)
        {
            try
            {
                var interviewShell = container.Resolve<InterviewModeShell>();
                var formShell = container.Resolve<FormModeShell>();
                var region = regionManager.Regions["ShellRegion"];
                switch (param)
                {
                    case "InterviewMode":
                        if (RegionHelper.GetView(region, "FormModeShell") != null)
                        {
                            var shellRegion = regionManager.Regions["ShellRegion"];
                            var view = shellRegion.GetView("FormModeShell");
                            region.Remove(view);
                        }
                        if (RegionHelper.GetView(region, "InterviewModeShell") == null)
                            region.Add(interviewShell, "InterviewModeShell");
                        region.Activate(interviewShell);
                        break;
                    case "FormMode":
                        if (RegionHelper.GetView(region, "InterviewModeShell") != null)
                        {
                            var shellRegion = regionManager.Regions["ShellRegion"];
                            var view = shellRegion.GetView("InterviewModeShell");
                            region.Remove(view);
                        }
                        if (RegionHelper.GetView(region, "FormModeShell") == null)
                            region.Add(formShell, "FormModeShell");
                        region.Activate(formShell);
                        break;
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        } 


Apr 28, 2011 at 7:00 AM

Heres your modified app. The problem was you were using ItemsControl for all your regions. ItemsControl uses AllAciveRegion so you cant deactive views in this kind og region. I changed them to ContentControls, which use SingleActiveRegion where you can deactivate views.

Also few things I noted

  • You need a lot of refactoring and clean up
  • Modules can be loosely coupled
  • Your InterViewModelShell and FormModeShell have regions with same name, like ContentRegion/TopRegion etc. which can cause issues, i.e region names clash. Either you need different names or make sure those sub regions are removed when you deactivate a view.

I would suggest you to have a look at the MEF way. Makes code very clean.

 

Apr 28, 2011 at 7:47 AM

Thank for your help.

Currently, I solved all problems I have.

There are some change is my code

  • Change global command to EventAggregator (It'll prevent call function many time).
  • Remove all current region before add other region (It'll prevent problem same region name name).

Can you explain more about modules loosely couple.

I'm very appreciate.

Apr 28, 2011 at 9:32 AM

By loosely coupled I mean modularising your app even more. You could create separate modules for the views you load in different regions. Also I noticed you have added reference to your modules project. Instead you could use modulemanager to download the xap when needed, i.e. on demand.

May 26, 2011 at 1:36 PM

Hi gan_s

Can you please check that the sample app that you included a link to in your post on Apr 26 at 6.33pm is still accessible? I've downloaded it and tried to open it with both WinZip and WinRar and I keep getting an error message indicating that the archive is damaged.  Maybe I'm doing something wrong.

Your replies to this discussion thread are very helpful and it would be great to be able to access the sample application.

Thanks.

 

May 26, 2011 at 2:34 PM

Sorry, I have got the download working now.

Thanks again for sharing the sample.