1

We're using Castle Windsor and Prism 4 (Feb 2010). We're using the Windsor bootstrapper that makes Castle play nice with Prism that was released in the CompositeWPFContrib package.

I'm trying to define regions on my main Shell's XAML. If I define one region, like so:

<ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.ToolBarRegion}"
                    DockPanel.Dock="Top"/>

And then do the following in one of my Modules Initialize method:

_regionManager.Regions[RegionNames.ToolBarRegion].Add(typeof(SomeView));

...life is good.

However, as soon as I add another region in the Shell's XAML:

<ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.WorkspaceRegion}"
                    DockPanel.Dock="Bottom"/>

And then do:

_regionManager.Regions[RegionNames.WorkspaceRegion].Add(typeof(SomeOtherView));

...I get the error: "The region manager does not contain the ToolBarRegion region."

What gives? As soon as I comment out the second region it finds the first, when I add the second region back in it blows up, as if the RegionManager refuses to hold a collection of regions. It should be said that this is my first foray into both Castle Windsor and Prism, so it's not out of the realm of possibility that I'm missing something painfully obvious here. Any light that could be shed on this would be most helpful.

riQQ
  • 9,878
  • 7
  • 49
  • 66
Scott
  • 513
  • 9
  • 20

1 Answers1

0

Are you sure it's DockPanel that you are adding your controls to? Maybe your container is a content control itself (kind of control that accepts only one child)?

Also, you could try register your region manager in the bootstrapper:

RegionManager.SetRegionManager(shell, this.Container.Resolve<IRegionManager>());

See the following questions:

Cannot find Region in RegionManager (using PRISM)

WPF, Prism v2, Region in a modal dialog, add region in code behind

EDIT

I looked at the sample solution (link in comments), and found out that your view injection code gets executed before main view is created. Your module initializers get called in StartRuntime->CreatePrismBootStrapper, and DisplayRootView (which creates your shell) is called later. Of course it can't find the region when the shell hasn't been created yet.

If all you want to register your subcontrols in module initialize code, view discovery is more suitable - it doesn't require your shell to be already created. View injection is better when you need to switch views based on user input (in this case making sure that containing control had been registered is up to you).

You have several options:

  1. Use view discovery - as you did in the sample solution.

  2. Create and register your Shell instance before loading your modules. base.DisplayRootView() should be able to find it in the container so It wouldn't create another. One way to do, but I'm not sure if best:

PrismBootstrapper.cs:

protected override DependencyObject CreateShell()
{
    Thor.Application.Views.ShellView view = new Thor.Application.Views.ShellView();
    _container.Register(Castle.MicroKernel.Registration.Component.For<Thor.Application.Views.ShellView>().Instance(view));
    // _container.Resolve<Thor.Application.Views.ShellView>();

    return view;
}

.3. CreatePrismBootstrapper() after base.DisplayRootView ? It doesn't work (NullPointerException on ServiceLocator and I'm not sure if it would make sense since I'm not really familiar with libraries used by you except Prism...

Hope this helps...

Community
  • 1
  • 1
surfen
  • 4,644
  • 3
  • 34
  • 46
  • There is a MainShellView, which is the Shell of the app. Inside the MainShellView is a MainSiteView, which is a UserControl, which contains the DockPanel referenced above. That DockPanel then contains the two ContentControls. As for the RegionManager, it is registered on the MainSiteView, not the MainShellView, if that has any bearing on things. If it's registered on the MainShellView it doesn't find any regions, registering it on the MainSiteView exhibits the described behavior. – Scott May 16 '11 at 21:55
  • Are you sure you don't nest your Regions? Try adding a simple control to the DockPanel and see if it stays there after adding a region. Maybe when the second region get's added it removes all other controls from DockPanel, as if the DockPanel was the actual region? – surfen May 16 '11 at 22:46
  • Here's the heirarchy: Our MainWindow is an Actipro RibbonWindow that we're creating manually in the bootstrapper. The MainWindow's content is set to MainShellView, which is a UserControl that has two ContentControls that overlap, one for the Workspace and another for Dialogs. The Workspace ContentControl is set to the MainSiteView at startup. MainSiteView has two ContentControls, one is the ToolBarRegion and the other is the WorkspaceRegion. I've tried registering the RM with the MainWindow, MainShellView, and MainSiteView and always get this problem. One region works, two regions fail. – Scott May 17 '11 at 15:52
  • have you tried inserting 2 regions in xaml but commenting out this `_regionManager.Regions[RegionNames.WorkspaceRegion].Add(typeof(SomeOtherView));` ? What is the result? Also check your constant value RegionNames.WorkspaceRegion for copy/paste error ("ToolBarRegion"?) – surfen May 18 '11 at 07:57
  • I've triple checked the copy/paste errors, so those can be ruled out. When I comment out the _regionManager code, and leave the two ContentControls in the XAML, each with their respective RegionNames associated with them, I get a shell with two empty content controls. So that "works," if you want to call it that. It's only when I try to actually reference the first region that it blows up. – Scott May 18 '11 at 19:50
  • Your comment suggests that you commented both _regionManager occurences. What happens when you do _regionManager code **on only one of the two ContentControls**? Is the second empty contentControl also on the shell, except the one filled by regionManager, or are all DockPanel items removed? You can try Adding dummy controls like buttons to check this. – surfen May 19 '11 at 05:57
  • I was getting sort of lost trying to do this in our main app. So I created a stand-alone app that mirrors our bootstrapping process and has a ShellView that has a single ContentControl region called MainSiteRegion. MainSiteRegion is to be populated by a UserControl called MainSiteView. If I use _regionManager.Regions["MainSiteRegion"].Add(view.GetType()); it says it can't find the MainSiteRegion. Same as I've been getting prior only now with a single region. If I use _regionManager.RegisterViewWithRegion("MainSiteRegion", view.GetType()); it works. Might it be how we're registering the RM? – Scott May 19 '11 at 17:14
  • If you're at all interested in seeing the stand-alone app let me know. – Scott May 19 '11 at 17:45
  • Yes, could you upload your sample solution somewhere? – surfen May 19 '11 at 20:48
  • The difference between these two approaches (view discovery-RegisterViewWithRegion and view injection-Region.Add) is that view discovery is independent of timing issues (view being constructed at the moment of displaying the region). On the other hand, in view injection at time when you call _regionManager.Regions["MainSiteRegion"].Add() you should already have your regions added to the shell(RM) (breakpoint and check which is first). Also, I'm pretty sure that Region.Add accepts instances of views, not their types, so it should be _regionMngr.Regions["MainSiteRegion"].Add(view), shouldn't it? – surfen May 19 '11 at 20:56
  • @surfen Here's a [link](http://wikisend.com/download/241642/ThorSolution.7z) to the download. There are a bunch of comments in the CoreUiModule file that detail what I've tried, etc. And the .Regions["MainSiteRegion"].Add does take a Type as its parameter. – Scott May 19 '11 at 23:34
  • I'll try this tomorrow, since I don't have access to VS2010 now. After a quick glance at code I don't understand how the ShellView gets created and displayed - could you explain? I don't see connection between ShellView and ShellViewModel (which is referenced in the bootstrapper). – surfen May 20 '11 at 07:02
  • @surfen We're using Caliburn.Micro as our MVVM framework. It uses naming conventions to do its binding, so ShellView and ShellViewModel are bound by their names automagically. The ShellView is being created in DisplayRootView (actually in base.DisplayRootView). A WindowManager then creates a Window class, resolves the View associated with the VM given to the Bootstrapper, and assigns the View associated with the VM to the Content property of the Window. In this case, it's ShellView because ShellViewModel is what the Bootstrapper is working with. HTH. – Scott May 20 '11 at 13:13
  • And I think that might be part of the problem. Because we're using the Caliburn bootstrapper in order to start the app, that has to then create another bootstrapper which is inherited from the WindsorBootstrapper which is a derivative of the PrismBootstrapper. In order to show the main Window and have all the closing logic wired up, we can't use CreateShell to create the MainWindow and register the RM with it. That's why I'm registering the RM with the _mainWindow variable in the ThorBootstrapper. I suspect something's not right with the RM as a result. – Scott May 20 '11 at 13:20
  • @Scott updated my answer with some findings based on supplied sample solution – surfen May 21 '11 at 21:13
  • @surfen, I appreciate your help but things just aren't working out on this end. Still getting missing regions and the like. It looks as if Prism and Caliburn might not like playing with each other. I'm going to pursue an alternative solution that may or may not involve Prism at this point. Thanks for your assistance and spending the time on the problem. – Scott May 31 '11 at 15:20