Shell regions not populated when hosted in an MFC CView

Topics: Prism v4 - WPF 4
Feb 9, 2012 at 9:49 PM

We are working on a new application that uses C#, WPF4, Prism4 and MEF.  The application comprises a main shell window which defines a grid with some splitters and five regions, and a number of separate modules that contribute UI functionality in to the various regions through view discovery and view injection.  All standard stuff, nothing exotic.  The application is very basic and everything works fine, i.e. the modules correctly contribute their views in to the shell's regions at run time.

We also have a requirement to host the same shell (and UI from the contributing modules) in to a large legacy MFC application we have.  Here's where we're having problems.  The WPF/MFC interop code (using HwndSource) seems to be working fine, as evidenced by the fact that the shell gets displayed correctly as a child of the parent MFC CView and has basic functionality like a grid splitter that is defined in the shell itself.  However, none of the regions in the shell are being populated with views defined in the Prism modules.  Debugging shows that the modules are indeed being loaded, however, the IRegionManager instance that gets injected in to each module contains zero regions for the module to add its views in to.  It's as if Prism is not aware that the shell defines any regions at all, consequently, attempts to add views in to these "non-existent" regions fail.

We derived a new custom bootstrapper class that our MFC code calls the Run() method on.  This bootstrapper class is identical to its equivalent in the standalone application (which works fine), the only difference is that we no longer override the InitializeShell() method, we just rely on the base class implementation.  Typically this method is overridden to set the Application.Current.MainWindow to the shell and then show the shell, however, in our case there is no current application because we're hosted inside an MFC app.  Various attempts at overriding the Bootstrapper's run functionality to yield control back to the MFC app to display the shell at the appropriate time have failed (failed in the sense that the shell's regions are still unpopulated, but the shell still displays).

Any advice on how to host a Prism-enabled shell with regions in an MFC CView and have the MFC application initiate the bootstrapping process would be appreciated.  Thanks.

Developer
Feb 10, 2012 at 6:34 PM

Hi,

Based on my understanding, Prism does not support this scenarios from out of the box.

On the other hand, I believe you could find the following thread interesting, where a Prism application hosted inside a regular window sample is proposed:

I hope you find this useful,

Agustin Adami
http://blogs.southworks.net/aadami

Feb 13, 2012 at 3:31 PM

Agustin,

Thank you for your quick reply and the sample you referenced.  I had tried out something somewhat similar to prove out that a shell implemented as a user control and defined in a class library can be hosted in a separate application's main window.

Of course what makes my situation different is the fact that I'm trying to host the usercontrol shell in an MFC application.  This means that I cannot set Application.Current.MainWindow because there is no .NET application, only an MFC one, and apparently this is critical to get Prism to identify the regions defined in the shell.

You mentioned that Prism does not support this scenario "out of the box".  Does this imply that with some specific customization that it is possible to make this work in an MFC application?  If so, would you mind giving me some direction on how to achieve it?

Thanks again for your help,
Paul

Feb 14, 2012 at 5:36 PM

Okay, I figured it out.  Painstakingly stepping through the Prism code, I came across a method on the RegionManager called OnSetRegionNameCallback().  This method conditionally calls CreateRegion() based on the result of another method call, IsInDesignMode().  If we are *not* in design mode, a region is created, otherwise no region is created.  Closer examination of IsInDesignMode revealed that three separate tests are made to determine if we are in "design mode" or not, and if any of them are true, it is considered that we are in design mode.  One of these checks was if Application.Current == null.  Of course, in the context of an MFC application, Application.Current is indeed null, so the determination (erroneously) was that we were in design mode, and therefore no regions were ever created.

Once I realized this, further internet searches showed a number of other people have run in to the same problem.  Indeed, there is even an issue logged in the Prism section of CodePlex (work item #3552) relating to this exact issue dating back to January 2009.  Contributors to this work item also suggests a work around of creating a dummy application just to pass the "are we in design mode?" check.  Please reference the work item for more details.  I implemented a similar workaround and was then able to successfully host my Prism-enabled shell and its contributing modules in an MFC CView in an MFC application.

Thank you to those who blazed this trail before me and identified and proposed a workaround.  You have saved me a lot of time!