2
votes

I'm using Prism in a ViewModel first approach, i.e.:

1) I register my ViewModels in a container (unity in this case) .

2) I supply a DataTemplate (UserControl) for each vm .

3) I navigate using the ViewModel name which I registered with the Container .

    _regionManager.RequestNavigate(regionName, viewModelName, navigationCallBack);  

This works fine , but when I attempt to remove the "View" from this region, I get the following exception :

 The region does not contain the specified view. Parameter name: view

I attempt to remove:

  var region = _regionManager.Regions[requests[i].RegionName];                                     
  var view = region.Views.Single(v => v.GetType().Name == requests[i].ViewName);
  region.Remove(view);   

The ViewModel is found in the "Views" collection. Any idea what is wrong and how to work around this?

2
compositewpf.codeplex.com/discussions/396304 My ViewModel was marked with IRegionMemberLifetime.KeepAlive and returned false , i don't know what the meaning of this is for Prism when removing a view but since i didn't need it for now i just removed it. - eran otzap

2 Answers

2
votes

If IRegionMemberLifetime.KeepAlive returns false, this will create a new view every time the view is navigated to. If you return True, you keep that view alive and return the same view when navigated to.

The reason you can't remove the view whilst using KeepAlive returning false is because technically the view is already being removed by the time you are calling to remove it. Instead of removing it, you will need to deactivate the view. Don't worry, the view will be removed from the collection and disposed of because of KeepAlive returning false, you are just really telling the UI to deactivate it.

var region = _regionManager.Regions[requests[i].RegionName];                                     
var view = region.Views.Single(v => v.GetType().Name == requests[i].ViewName);
region.Deactivate(view);   

Just to reiterate -

  • KeepAlive returning False = region.Deactivate(view)
  • KeepAlive returning True = region.Remove(view)
2
votes

Thanks to TrialAndError's answer, I found the deactivating items if the KeepAlive is false solved my problems, however all of our classes were setup with a KeepAlive attribute rather than by implementing the IRegionMemberLifetime interface, which made checking the KeepAlive a little tricky. I came up with this loop which we use to unload all views from a region. I hope this helps someone. This works with both the IRegionMemberLifetime interface and the RegionLifetimeAttribue where KeepAlive is set to false.

 public static void RemoveAllViews(this IRegion region)
    {
        /*
          * If KeepAlive == false we must deactiveate rather than trying to remove it.
          * KeepAlive can be set by implementing IRegionMemberLifetime interface, or by setting the KeepAlive attribute, 
          * so we must check both. 
          * Use reflection to determine if the view has a KeepAlive attribute, and if it does, then is KeepAlive == false. 
          * 
         * */ 
        foreach (object view in region.Views)
        {
            Type type = view.GetType();
            if (null != Attribute.GetCustomAttribute(type, typeof(RegionMemberLifetimeAttribute)))
            {
                RegionMemberLifetimeAttribute attribute = (RegionMemberLifetimeAttribute)Attribute.GetCustomAttribute(type, typeof(RegionMemberLifetimeAttribute));
                if (attribute.KeepAlive == false)
                    region.Deactivate(view);
            }
            else if (view is IRegionMemberLifetime && !((IRegionMemberLifetime)view).KeepAlive)
            {
                region.Deactivate(view);
            } 
            else //This is not an item that has KeepAlive set to false so remove it
            {
                region.Remove(view); 
            } 
        }
    }