RegionManager (Prism4)

Topics: Prism v4 - WPF 4
Jun 15, 2010 at 3:58 PM
Walking thru the debugger regions get registered but grabbing the regionmanager in the module doesn't show any regions available. Anyone else seeing this...
Jun 17, 2010 at 2:11 PM

hi mvermeg i resolved this in mef with this chage in mefMefBootstrapper.cs

public void Run(bool runWithDefaultConfiguration)
        {
            this.CreateLogger();
            this.Logger.Log("Logger was created successfully.", Category.Debug, Priority.Low);

            this.Logger.Log("Creating module catalog.", Category.Debug, Priority.Low);
            this.CreateModuleCatalog();

            this.Logger.Log("Configuring module catalog.", Category.Debug, Priority.Low);
            this.ConfigureModuleCatalog();

            this.Logger.Log("Creating catalog for MEF", Category.Debug, Priority.Low);
            this.CreateAggregateCatalog();

            this.Logger.Log("Configuring catalog for MEF", Category.Debug, Priority.Low);
            this.ConfigureAggregateCatalog();

            this.Logger.Log("Creating Mef container", Category.Debug, Priority.Low);
            this.CreateContainer();

            this.Logger.Log("Configuring MEF container", Category.Debug, Priority.Low);
            this.ConfigureContainer();

            this.Logger.Log("Configuring region adapters", Category.Debug, Priority.Low);
            this.ConfigureRegionAdapterMappings();

            this.Logger.Log("Configuring default region behaviors", Category.Debug, Priority.Low);
            this.ConfigureDefaultRegionBehaviors();

            this.Logger.Log("Registering Framework Exception Types", Category.Debug, Priority.Low);
            this.RegisterFrameworkExceptionTypes();

            this.Logger.Log("Creating shell", Category.Debug, Priority.Low);
            this.Shell = this.CreateShell();
            if (this.Shell != null)
            {
                this.Logger.Log("Initializing shell", Category.Debug, Priority.Low);
                this.InitializeShell();

                //Correct for work IRegionManager
                //HERE
                var region=this.Container.Providers[0].GetExport<IRegionManager>();
                RegionManager.SetRegionManager(this.Shell, region.Value);
                this.Container.ComposeExportedValue<IRegionManager>(region.Value);
                RegionManager.UpdateRegions();
            }

            this.Logger.Log("Initializing modules", Category.Debug, Priority.Low);
            this.InitializeModules();           

            this.Logger.Log("Bootstrapping complete", Category.Debug, Priority.Low);
        }

 

i just create IRegionManager and register the instance, and works for me i hope you can resolve your trouble.

Juan Guillermo

Colombia-Medellin

Jun 17, 2010 at 4:19 PM
Edited Jun 17, 2010 at 4:19 PM

hi again mvermeg, the last solution only works with only one region, im trying to figure out how to resolve , when i have a solution i give it to you.

Juan Guillermo

Colombia-Medellin

 

Jun 17, 2010 at 4:22 PM
Edited Jun 17, 2010 at 4:23 PM

Juan,

the way I am setting up my project to have a the "Shell" which will have only 1 region "ShellRegion".  When the project starts it will look for a Module named Shell. This module contains the regions for the actual layout.  Unless I am doing something horriblely wrong it doesn't pickup those regions and fails based on not finding the "MainRegion".

So your solution partially works at this point...  Btw thanks :)

 

Edit:  I believe it has to do with the visualtree not seeing the additional regions..

 

Morgan Vermef

Jun 17, 2010 at 5:21 PM

Hi Morgan.

 

Ready, you only need put this metadata [System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)] for all class in the folder Regios/Behaviors

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(AutoPopulateRegionBehavior))]
    public class MefAutoPopulateRegionBehavior : AutoPopulateRegionBehavior

 [System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(BindRegionContextToDependencyObjectBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(DelayedRegionCreationBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(RegionActiveAwareBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(DelayedRegionCreationBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(RegionManagerRegistrationBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(SyncRegionContextWithHostBehavior))]

[System.ComponentModel.Composition.PartCreationPolicy(CreationPolicy.NonShared)]
    [Export(typeof(SelectorItemsSourceSyncBehavior))]

its only was taking one region because the Container was shared the instance the all behaviors so first DelayedRegionCreationBehavior take the first region and when take other region its update the TargetElement

 private static void CreateRegion(DependencyObject element)
        {
            IServiceLocator locator = ServiceLocator.Current;
            //Get the same instance
            DelayedRegionCreationBehavior regionCreationBehavior = locator.GetInstance<DelayedRegionCreationBehavior>();
            //HERE
            regionCreationBehavior.TargetElement = element;
            regionCreationBehavior.Attach();
        }

so its only load the first or last region, the second trouble was with behaviors, when you set

protected virtual void AttachDefaultBehaviors(IRegion region, T regionTarget)
        {
            IRegionBehaviorFactory behaviorFactory = this.RegionBehaviorFactory;
            if (behaviorFactory != null)
            {
                DependencyObject dependencyObjectRegionTarget = regionTarget as DependencyObject;

                foreach (string behaviorKey in behaviorFactory)
                {
                    if (!region.Behaviors.ContainsKey(behaviorKey))
                    {
                        IRegionBehavior behavior = behaviorFactory.CreateFromKey(behaviorKey);

                        if (dependencyObjectRegionTarget != null)
                        {
                            IHostAwareRegionBehavior hostAwareRegionBehavior = behavior as IHostAwareRegionBehavior;
                            if (hostAwareRegionBehavior != null)
                            {
                                //HERE line2
                                hostAwareRegionBehavior.HostControl = dependencyObjectRegionTarget;
                            }
                        }

                        //HERE line1
                        region.Behaviors.Add(behaviorKey, behavior);
                    }
                }
            }
        }

you get an error that said "The Region property cannot be set after Attach method has been called." in line1 and in line2 you get an error that said "The HostControl property cannot be set after Attach method has been called."

so this is what happen here just add this metadata and all works perfect if you see more errors please tell me, in this moment im working on project that use mef and composite, so thats why i was correcting this errors.

 

Juan Guillermo

Colombia-Medellin

Jun 18, 2010 at 7:57 PM

that has it...

seems to be working well now.  Just have to get my viewmodels working correctly :)

Jun 18, 2010 at 8:03 PM

hi morgan

if you use viewmodels and views take care about two things:

1- in your view you must add the Export metadata, like this:

[Export(typeof(AnalisisBasicoView))]
    public partial class AnalisisBasicoView : UserControl

 

2-in your viewmodel do something like this:

 [Export(typeof(AnalisisBasicoViewModel))]
    public class AnalisisBasicoViewModel
    {
        private readonly AnalisisBasicoView _view;

        [ImportingConstructor]
        public AnalisisBasicoViewModel(AnalisisBasicoView view)
        {
            _view = view;
        }

        public UserControl View { get { return _view; } }
    }

Juan Guillermo

Colombia-Medellin

Jun 19, 2010 at 2:47 AM

Just as a comment on the last post. You don't need to explicitly specify type i.e. AnalysisBasicView if the type you are exporting is the concrete type. You only need to specify if you want it to be one of the interfaces it implements / classes it derives from (UserControl).

 

Jun 20, 2010 at 2:10 PM
thx gblock for you commetn, but im not agree with you for this example, cause my viewModel need AnalisisBasicoView, and if you have a lot of view exporting like UserControl, Hwo could you determine wich is the right for the viewModel, and i was giving some example based on Unity. Just it. Once Again for this particullary example. Juan Guillermo Colombia-Medellin
Jun 20, 2010 at 6:06 PM

I think there is a misunderstanding of what I meant. I am not suggesting that you export UserControl. What I am saying is if you put an Export on AnalisisBasicoView / AnalisisBasicoViewModel without specfying the type explicitly we default to the concrete type in other words...

[Export(typeof(AnalisisBasicoViewModel))]
public class AnalisisBasicoViewModel {
}

Is identical to:

[Export]
public class AnalisisBasicoViewModel {
}

As we will use the concrete type as the contract.

If however your view model implemented an interface that you wanted to export then you need to be explicit: 

[Export(typeof(IAnalisisBasicoViewModel))]
public class AnalisisBasicoViewModel : IAnalisisBasicoViewModel {
}

 Or you can use an InheritedExport on the interface which will automatically result in it being exported by an implementer.

//no export is required because the interface provides it.
public class AnalisisBasicoViewModel : IAnalisisBasicoViewModel {
}

[InheritedExport]
public interface IAnalisisBasicoViewModel {
}

 Regards

Jun 21, 2010 at 3:50 AM

@Juan, sorry I wasn't very clear when I made the comment about getting my vm's working correctly.  I meant to say wire them up :)

@Glenn, right now I am using MEF to import the vm into the view and assign the datacontext the vm something to the nature of your blog back in march of this year (part of one of your refactoring runs).  Everything works even came across Grench's post related to using an attach property for relating view to vm, tried didn't like that approach for one I found that it wasn't working presently with this drop. 

what I got out of your post is now that I should go back and make more concrete contracts via implementing interfaces.  i haven't been using the object type to create the contract but string soup
(probably a bad idea) e.g. [Export("SomeViewModel")]

Morgan.