Same View Multiple Tabs and also inherit from Parent

Topics: Prism v4 - WPF 4
Jul 23, 2012 at 9:54 PM

Tabitem1 in my shell.xaml is opening a View1 which is a tab control and has a region that points to view2. Multiple Views of view2 are being added to the TabControl in View1 using a Controller class.

In the Controller class it adds the view2 to the Tab control in view1.

The code in my View1 controller classs is as follows:

  View2  view2 =  new   View2  ();

view2.View2ViewModel = _serviceLocator.GetInstance< View2ViewModel>();

view2.PatientViewModel.Model = p;

_regionManager.Regions[RegionNames .View2TabsRegion].Add(view2, p.pGUID.ToString(), false);

_regionManager.Regions[RegionNames  . View2TabsRegion].Activate(view2);

  In View2 in one of the Wpf grid I have another content control with regions that opens up view3. View3 has a tab control in which one of the tab items region is view4.

View3 calls another controller class with the following signature:

[ImportingConstructor]

 public View3Controller(IRegionManager regionManager, IServiceLocator serviceLocator, IEventAggregator eventAggregator)

{

_eventAggregator = eventAggregator;

_serviceLocator = serviceLocator;

 _regionManager = regionManager;

 _eventAggregator.GetEvent<NewForm>().Subscribe(this.AddNewForm, ThreadOption.UIThread, true);

 }

This is how i am Adding the RegistredViews

private void AddRegisteredViews()

{

 if (this.Region != null)

{

 foreach (var viewEntry in this.RegisteredViews)

{

 if (viewEntry.Metadata.RegionName == this.Region.Name)

{

 Var view = viewEntry.Value;

 if (!this.Region.Views.Contains(view))

{

 this.Region.Add(view);

}

}

}

}

}

Here is my problem now.

 

 

 

Developer
Jul 24, 2012 at 1:36 PM

Hi,

It would be helpful, if you could provide us with a little more information about the problem you are experiencing, for example if the application is throwing an exception, etc.

So far, based on my understanding of your scenario, I found that you were adding several instances of "view2" to a region. And as this view has its own region, the second registration of this view could produce an error, as the RegionManager allows only uniquely named regions. If this is your problem, you could try using scoped region managers to avoid it.

If this is your case, you could find more information about it in the following section of the Prism documentation:

Regards,

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

Jul 24, 2012 at 5:55 PM

@Adami,

Yes i am getting the error that View is already registered for the second tab that i open.

I did go through the article but i am not registering my views to the regions in my code and i cannot do so as per my code above since the regions are being described in XAML and not code behind. So is there any possible alternative?

Developer
Jul 24, 2012 at 9:32 PM

Hi,

I believe, I'm not understanding your scenario completely, it would be helpful if you could provide us with more information on how you are implementing this.

So far, as mentioned before if the exception thrown is this: "Region with the given name is already registered:", as far as I know using scoped region managers will be the recommended approach.

Also, take into account that by default in Prism when a view or control is added to the visual tree as a child of another control or region, any region defined in the control should be registered in the RegionManager of the parent control. The RegionManagerRegistrationBehavior, is responsible of this behavior and for making sure that the region is registered to the correct RegionManager automatically.

Regards,

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

Jul 25, 2012 at 2:14 PM
Edited Jul 25, 2012 at 2:20 PM

Aadami,

Here is my problem. When i use the following code

_regionManager.Regions[RegionNames .View2TabsRegion].Add(view2, p.pGUID.ToString(), true);

I can create multiple tabs of view2 in View1, because this creates a local manager scope. View2 has a region manager that opens up View3. View3 has a tab control that needs to add mutiple tabs of View4.

By using the above line of code the global region manager does not recognise the View3 region in View2 because it now belongs in a local scoped region manager but i cannot access the local region manager at View3 level because the view is being generated in XAML and not in code.

If i set the

_regionManager.Regions[RegionNames .View2TabsRegion].Add(view2, p.pGUID.ToString(), false);  the global region manager does read all the regions upto View4.

which i what i want but now i cannot add multiple tabs of View2 to View1. The exception that it gives me at this point is: "Update Region Exception was unhandled by user code" and the message is:

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. ---> Microsoft.Practices.Prism.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. ---> Microsoft.Practices.Prism.Regions.Behaviors.RegionCreationException: An exception occurred while creating a region with name 'View4Region'. The exception was: System.ArgumentException: Region with the given name is already registered: View4Region
   at Microsoft.Practices.Prism.Regions.RegionManager.RegionCollection.Add(IRegion region)
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.StartMonitoringRegionManager()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.OnAttach()
   at Microsoft.Practices.Prism.Regions.RegionBehavior.Attach()
   at Microsoft.Practices.Prism.Regions.RegionBehaviorCollection.Add(String key, IRegionBehavior regionBehavior)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.AttachDefaultBehaviors(IRegion region, T regionTarget)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Initialize(T regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Microsoft.Practices.Prism.Regions.IRegionAdapter.Initialize(Object regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName).  ---> System.ArgumentException: Region with the given name is already registered: View4Region
   at Microsoft.Practices.Prism.Regions.RegionManager.RegionCollection.Add(IRegion region)
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.StartMonitoringRegionManager()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.OnAttach()
   at Microsoft.Practices.Prism.Regions.RegionBehavior.Attach()
   at Microsoft.Practices.Prism.Regions.RegionBehaviorCollection.Add(String key, IRegionBehavior regionBehavior)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.AttachDefaultBehaviors(IRegion region, T regionTarget)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Initialize(T regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Microsoft.Practices.Prism.Regions.IRegionAdapter.Initialize(Object regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
   --- End of inner exception stack trace ---
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.TryCreateRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.OnUpdatingRegions(Object sender, EventArgs e)
   --- 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.Prism.Events.WeakDelegatesManager.Raise(Object[] args)
   at Microsoft.Practices.Prism.Regions.RegionManager.UpdateRegions()'.
    But also check the InnerExceptions for more detail or call .GetRootException().  ---> Microsoft.Practices.Prism.Regions.Behaviors.RegionCreationException: An exception occurred while creating a region with name 'View4Region'. The exception was: System.ArgumentException: Region with the given name is already registered: View4Region
   at Microsoft.Practices.Prism.Regions.RegionManager.RegionCollection.Add(IRegion region)
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.StartMonitoringRegionManager()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.OnAttach()
   at Microsoft.Practices.Prism.Regions.RegionBehavior.Attach()
   at Microsoft.Practices.Prism.Regions.RegionBehaviorCollection.Add(String key, IRegionBehavior regionBehavior)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.AttachDefaultBehaviors(IRegion region, T regionTarget)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Initialize(T regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Microsoft.Practices.Prism.Regions.IRegionAdapter.Initialize(Object regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName).  ---> System.ArgumentException: Region with the given name is already registered: View4Region
   at Microsoft.Practices.Prism.Regions.RegionManager.RegionCollection.Add(IRegion region)
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.StartMonitoringRegionManager()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.OnAttach()
   at Microsoft.Practices.Prism.Regions.RegionBehavior.Attach()
   at Microsoft.Practices.Prism.Regions.RegionBehaviorCollection.Add(String key, IRegionBehavior regionBehavior)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.AttachDefaultBehaviors(IRegion region, T regionTarget)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Initialize(T regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.RegionAdapterBase`1.Microsoft.Practices.Prism.Regions.IRegionAdapter.Initialize(Object regionTarget, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
   --- End of inner exception stack trace ---
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.TryCreateRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.DelayedRegionCreationBehavior.OnUpdatingRegions(Object sender, EventArgs e)
   --- End of inner exception stack trace ---
   at Microsoft.Practices.Prism.Regions.RegionManager.UpdateRegions()
   at Microsoft.Practices.Prism.Regions.RegionManager.RegionCollection.Add(IRegion region)
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.TryRegisterRegion()
   at Microsoft.Practices.Prism.Regions.Behaviors.RegionManagerRegistrationBehavior.OnUpdatingRegions(Object sender, EventArgs e)
   --- 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.Prism.Events.WeakDelegatesManager.Raise(Object[] args)
   at Microsoft.Practices.Prism.Regions.RegionManager.UpdateRegions()'.
    But also check the InnerExceptions for more detail or call .GetRootException().

Developer
Jul 25, 2012 at 5:36 PM
Edited Jul 25, 2012 at 5:38 PM

Hi,

As far as I know, if you want to use multiple instances of the same view which contains a region, you will have to use scoped region managers to avoid this error. Take into account that when using scoped region manager you may have to define a custom logic to retain the new RegionManager instance (which is returned by the Region.Add method) in order to have further access to the regions defined inside this scope as the regions in views added this way won't be available in the global region manager. Note that this implementation will depend on your personal preferences and the requirements of your scenario.

For example, a possible approach could be to implement a shared service which keeps a reference to all the created scoped region managers and defines a logic to access them. This way every time that you create an scoped region, you should register the new region manager in this service. Then in your controller classes you could consume this service, to locate the corresponding RegionManager and access the inner regions.

You could find more information about shared services in the following chapter of the Prism documentation:

I hope you find this handy,

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