UpdateRegionsException when adding/removing a view with a scoped region manager

Topics: Prism v2 - WPF 4
May 26, 2010 at 12:22 PM
Hello,

we are using Prism in our application and I might have found a bug in the CAL.

We are using a view with a scoped region which is added to the MainRegion of the shell. The view is pretty simple:

<
UserControl x:Class="PatientManagement.Views.PatientManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/CompositeWPF">
<TabControl cal:RegionManager.RegionName="Exam" />
</UserControl>
Depending on the user input the view is added and removed from the MainRegion multiple times. I created a simple
module wich does add and remove the view multiple times. After the second Remove you always get a
 UpdateRegionsException
informing you that the Region with the name Exam already exists. (See stacktrache below)

public
class PatientManagementModule : IModule { private readonly IRegionManager _regionManager; private PatientManagementView _view; public PatientManagementModule(IRegionManager regionManager) { _regionManager = regionManager; } public void Initialize() { // Create view _view = new PatientManagementView(); AddView(); RemoveView(); AddView(); RemoveView(); // Exception! } public void AddView() { IRegion region = _regionManager.Regions["MainRegion"]; // Add the view to the region and create a scoped region manager region.Add(_view, "dummy", true); region.Activate(_view); } public void RemoveView() { IRegion region = _regionManager.Regions["MainRegion"]; // Remove the view from the region region.Remove(_view); } }
I used the debugger to step into the CAL code and found one problem. Whenever a view is added to a region, the Region.Add
Method will add the RegionManager as an attached property to the view. In the example the ScopedRegionManager is added
to the view as a attached property. Once you remove the view from the region, the Region.Remove will remove the
attached property only if it is the default RegionManager. So in the example the attached property is not removed because
it is the scoped RegionManager not the default one.

Once I added some code to remove the left over attached property from the view I can add and remove it
as often as I want without getting any exceptions.

Sincerely,

Michael

Stacktrace

Microsoft.Practices.Composite.Presentation.Regions.UpdateRegionsException: An exception occurred while trying to create region objects.
    - The most likely causing exception was: 'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Region with the given name is already registered: Exam
   at Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionCollection.Add(IRegion region) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\RegionManager.cs:line 315
   at Microsoft.Practices.Composite.Presentation.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion() in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\Behaviors\RegionManagerRegistrationBehavior.cs:line 127
   at Microsoft.Practices.Composite.Presentation.Regions.Behaviors.RegionManagerRegistrationBehavior.OnUpdatingRegions(Object sender, EventArgs e) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\Behaviors\RegionManagerRegistrationBehavior.cs:line 142
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Delegate.DynamicInvoke(Object[] args)
   at Microsoft.Practices.Composite.Presentation.Events.WeakDelegatesManager.Raise(Object[] args) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Events\WeakDelegatesManager.cs:line 49
   at Microsoft.Practices.Composite.Presentation.Regions.RegionManager.UpdateRegions() in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\RegionManager.cs:line 217'.
    But also check the InnerExceptions for more detail or call .GetRootException().  ---> System.ArgumentException: Region with the given name is already registered: Exam
   at Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionCollection.Add(IRegion region) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\RegionManager.cs:line 315
   at Microsoft.Practices.Composite.Presentation.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion() in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\Behaviors\RegionManagerRegistrationBehavior.cs:line 127
   at Microsoft.Practices.Composite.Presentation.Regions.Behaviors.RegionManagerRegistrationBehavior.OnUpdatingRegions(Object sender, EventArgs e) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\Behaviors\RegionManagerRegistrationBehavior.cs:line 142
   --- End of inner exception stack trace ---
   at Microsoft.Practices.Composite.Presentation.Regions.RegionManager.UpdateRegions() in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\RegionManager.cs:line 223
   at Microsoft.Practices.Composite.Presentation.Regions.RegionManager.RegionCollection.get_Item(String regionName) in C:\CSharp\PrismScopedRegions\CAL\Composite.Presentation\Regions\RegionManager.cs:line 292
   at PatientManagement.PatientManagementModule.RemoveView() in C:\CSharp\PrismScopedRegions\PatientManagement\PatientManagementModule.cs:line 51
   at PatientManagement.PatientManagementModule.Initialize() in C:\CSharp\PrismScopedRegions\PatientManagement\PatientManagementModule.cs:line 30

 

 

Jun 17, 2010 at 5:58 PM

Hi Michael,

Thanks for reporting that, we’ve checked your approach and some others, and found that it is an issue in Prism. We will communicate it to the Prism team to get them notified about it.
Based on our findings for your particular situation, a possible workaround without modifying the CAL is to change the place where the application is retrieving the Main Region, since it is not necessary to perform this operation on each adding/removing of a view.

The code for achieving that could look like this:

public class HelloWorldModule : IModule
{
    private IRegion MainRegion { get; set; }
    private Views.HelloWorldView MyView { get; set; }
    //public IRegionManager RegionManager { get; set; }
    
    public HelloWorldModule(IRegionManager regionManager)
    {
        // We added here the call for getting the main region 
        this.MainRegion = regionManager.Regions["MainRegion"];
    }

    public void Initialize()
    {
        this.MyView = new Views.HelloWorldView();
        this.AddView();            
        this.RemoveView();
        this.AddView();
        this.RemoveView();
    }

    public void AddView()
    {
        //We removed this call since it is not necessary to be repeated on each adding of a view.          
        //this.MainRegion = this.RegionManager.Regions["MainRegion"];            
        this.MainRegion.Add(this.MyView, "HelloWorldView", true);
        this.MainRegion.Activate(this.MyView);
    }

    public void RemoveView()
    {
        //We removed this call since it is not necessary to be repeated on each removing of a view. 
        //this.MainRegion = this.RegionManager.Regions["MainRegion"];
        this.MainRegion.Remove(this.MyView);
    }        
}

I hope you can find this helpful.

Fernando Antivero
http://blogs.southworks.net/fantivero

Jun 24, 2010 at 12:44 PM

How do you remove the view with the scopedregionmanager? And dispose scopedregionmanager from container?

Oct 15, 2010 at 4:40 PM

Hello Fernando,

Yes indeed very usefull ...

I'm facing exactly the same issue,

but in my case , when i use your solution, (scope limited) the subregions of my view are not included in the regionManager.

So, in one case, it works for Display, Remove, Display , and crach for Remove again

And, with your solution, It fail , when I'm trying to inject the view in the sub region (because not existing in the regionManager due to the scopped == true)

Do you have an idee .

Thanks in advance for your reply.

Best regards

    Christophe

Oct 15, 2010 at 7:52 PM

Hi Christophe,

Thanks for reporting that. I will copy this as a work-item, so the product team will be notified. Additionally, other users can vote this.

When you use an Scope Region, it will create a Region Manager separated. In general, scope regions are used with View Discovery, but we used this with View Injection as a workaround.

From the MSDN documentation: Note that by setting the createRegionManagerScope parameter to true, the added view will define a new region scope; therefore, all the regions registered by the view will not be registered with the Shell window's region manager;

Therefore, when you call to Add method in your MainRegion, you could register in your container the ScopedRegionManager returned

var scopedRegionManager = this.MainRegion.Add(this.MyView, "HelloWorldView", true);
yourContainer.RegisterInstanace(scopedRegionManager, "ScopedRegionManager")
;

Then you could use the container to obtain the scopedRegionManager for injecting your views.

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

 

Oct 15, 2010 at 7:53 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Oct 28, 2010 at 9:02 AM

Have we found a solution to this one? I think I've runned into a similar issue here: http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=232334

Nov 20, 2010 at 8:21 PM

This also appears to be an issue when moving views between regions. If a view with a scoped region manager is removed from one region, and subsequently re-added to another region, this issue also occurs. Forcing the view to clear it's RegionManagerProperty when removing from a region does prevent the exception as well.