PRISM + MEF -- Can't get regions to work properly

4.8k views Asked by At

a bit new to Prismv4 and MEF.

I went through the QuickStarts and tried to combine two of them together, but I can't seem to get it working.

First, I got a Bootstrapper to load the Shell Window.

public sealed class ClientBootstrapper : MefBootstrapper
{
    protected override void ConfigureAggregateCatalog()
    {
        base.ConfigureAggregateCatalog();

        //Add this assembly to export ModuleTracker (Shell is in this Assembly).
        AggregateCatalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
    }

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

    protected override void InitializeShell()
    {
        base.InitializeShell();

        Application.Current.MainWindow = (Window)Shell;
        Application.Current.MainWindow.Show();
    }
}

This worked fine. The Shell window was shown and a nice Hello World message appeared. Then I tried to create a Region inside the Shell window so I can load a View into that region. I haven't even gotten this to work to even look at moving it to an outside assembly.

[ModuleExport(typeof(HelloWorldModule), InitializationMode = InitializationMode.OnDemand)]
public class HelloWorldModule : IModule
{
    [Import(AllowRecomposition = true)]
    private IRegionViewRegistry regionViewRegistry;

    [ImportingConstructor()]
    public HelloWorldModule(IRegionViewRegistry registry)
    {
        this.regionViewRegistry = registry;
    }

    public void Initialize()
    {
        regionViewRegistry.RegisterViewWithRegion("PrimaryRegion", typeof(Views.HelloWorldView));
    }
}

The HelloWorld view (just a simple UserControl that contains a TextBlock) is not being loaded into the region! I guess I'm a bit lost here on how to load in my regions.

5

There are 5 answers

0
Michael Ulmann On

It looks like you're trying to use the view discovery approach?

Have you tried the following:

    [ModuleExport(typeof(HelloWorldModule), InitializationMode = InitializationMode.OnDemand)]
public class HelloWorldModule : IModule
{
    private IRegionManager regionManager;      

    [ImportingConstructor]
    public HelloWorldModule(IRegionManager regionManager)
    {
        this.regionManager = regionManager;
    } 

    public void Initialize()
    {
        this.regionManager.RegisterViewWithRegion("PrimaryRegion", typeof(Views.HelloWorldView));
    }
}
0
JLaanstra On

It's hard to tell what's going wrong based on the information you share. I would suggest looking at the examples and the reference implementation that comes with PRISM4. I guess the reference implementation and a little debugging should help you in finding the problem.

2
rajiv chaudhary On
public class ModuleC : IModule
{
    #region IModule Members

    /// <summary>
    /// Initializes the module.
    /// </summary>
    public void Initialize()
    {
        /* We register always-available controls with the Prism Region Manager, and on-demand 
         * controls with the DI container. On-demand controls will be loaded when we invoke
         * IRegionManager.RequestNavigate() to load the controls. */

        // Register task button with Prism Region
        var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
        regionManager.RegisterViewWithRegion("TaskButtonRegion", typeof(ModuleBTaskButton));

        /* View objects have to be registered with Unity using the overload shown below. By
         * default, Unity resolves view objects as type System.Object, which this overload 
         * maps to the correct view type. See "Developer's Guide to Microsoft Prism" (Ver 4), 
         * p. 120. */

        // Register other view objects with DI Container (Unity)
        var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
        container.RegisterType<Object, ModuleBRibbonTab>("ModuleBRibbonTab");
        container.RegisterType<Object, ModuleBNavigator>("ModuleBNavigator");
        container.RegisterType<Object, ModuleBWorkspace>("ModuleBWorkspace");
    }
}
0
cbeall On

Your ConfigureAggregateCatalog method in your bootstrapper needs to add the assembly that your view is in. Adding the line below to the end of the method should get you past your current problem.

this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Views.HelloWorld).Assembly));

This can also be done in XAML in a ModuleCatalog.

Your Views.HelloWorld class will also need an [Export] attribute added to it.

0
Danny On

You can try this and it works for me, the Module class as follows:

[ModuleExport(typeof(HelloWorldModule))]
public class HelloWorldModule : IModule
{

    [Import]
    private IRegionManager regionManager;

    public void Initialize()
    {
        Uri viewNav = new Uri("HelloWorldView", UriKind.Relative);
        regionManager.RequestNavigate("PrimaryRegion", viewNav);
    }
}

The View class as follows:

[Export("HelloWorldView")]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class HelloWorldView : UserControl
{
    public HelloWorldView()
    {
        InitializeComponent();
    }
}

The xaml in HelloWorldView

<UserControl x:Class="HelloWorldModule.HelloWorldView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <TextBlock>Hello World</TextBlock>
</Grid>
</UserControl>

You will need

protected override void ConfigureAggregateCatalog()
    {
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstapper).Assembly));
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(HelloWorldModule.HelloWorldModule).Assembly));

    }