Thursday, December 20, 2012

WPF PRISM: IRegionMemberLifetime KeepAlive doesn't get called

WPF PRISM: IRegionMemberLifetime KeepAlive doesn't get called

I have a need to switch the view being displayed based on a certain condition. I have implemented the switching logic in the constructor of the ViewModel

I am implementing IRegionMemberLifetime on the View and setting KeepAlive to false so that I always get a new instance of the View and the ViewModel.

But for some reason, when I click on the Navigation Button, my breakpoint at KeepAlive never reaches and I get the MainView instead of the WelcomeView.

Could you please help me out?

Here is the code for your reference:

Navigation Button:

<Controls:SignedButton VerticalAlignment="Top" Width="275" Height="45"     Foreground="#FFFFFF"      LeftSign="&lt;" Text="Back to Accounts"      TextSize="20" ButtonBackground="#666666"      HoverBackground="#0FBDAC" HoverOpacity="1" Margin="0,25,0,0"     Command="{x:Static Infrastructure:ApplicationCommands.NavigateCommand}"     CommandParameter="{x:Type Views:MainView}"/> 

View Model:

[RegionMemberLifetime(KeepAlive = false)] public class MainViewModel : ViewModel, IMainViewModel {     private readonly IUnityContainer _container;     private readonly IRegionManager _regionManager;      public MainViewModel(IUnityContainer container, IRegionManager regionManager)     {         _container = container;         _regionManager = regionManager;          Accounts = new List<Account>();          if (Accounts.Any()) return;          IRegion region = _regionManager.Regions[Regions.Main];          var views = region.Views;         foreach (var view in views)         {             region.Remove(view);         }          region.Add(_container.Resolve<IWelcomeView>());     }      public IList<Account> Accounts { get; private set; } } 

View Model Base:

public abstract class ViewModel : IViewModel {     protected virtual void OnPropertyChanged(string propertyName)     {         PropertyChangedEventHandler handler = PropertyChanged;         if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));     }      public event PropertyChangedEventHandler PropertyChanged; } 

View:

[RegionMemberLifetime(KeepAlive = false)] public partial class MainView : UserControl, IMainView {     public MainView(IMainViewModel mainViewModel)     {         InitializeComponent();          ViewModel = mainViewModel;     }      public IViewModel ViewModel     {         get { return (IViewModel) DataContext; }         set { DataContext = value; }     } } 

Shell View Model:

public class ShellViewModel : ViewModel, IShellViewModel {     private readonly IRegionManager _regionManager;      public ShellViewModel(IRegionManager regionManager)     {         _regionManager = regionManager;          NavigateCommand = new DelegateCommand<object>(Navigate);         ApplicationCommands.NavigateCommand.RegisterCommand(NavigateCommand);     }      private void Navigate(object navigatePath)     {         if (navigatePath != null)         {             _regionManager.RequestNavigate(Regions.Main, navigatePath.ToString());         }     }      public DelegateCommand<object> NavigateCommand { get; private set; } } 

Thanks a lot for looking into this :)

Answers & Comments...

Answer: 1

It would be useful for you to look into the RegionMemberLifetimeBehavior class in the Prism Library (for me, it is at C:\Prism4\PrismLibrary\Desktop\Prism\Regions\Behaviors)

Both the IRegionMemberLifetime interface and the RegionMemberLifetimeAttribute accomplish the same thing and can be defined on either your View or your ViewModel (provided the viewmodel is set to DataContext).

Here's the code that is relevant:

private void OnActiveViewsChanged(object sender, NotifyCollectionChangedEventArgs e)     {         // We only pay attention to items removed from the ActiveViews list.         // Thus, we expect that any ICollectionView implementation would         // always raise a remove and we don't handle any resets         // unless we wanted to start tracking views that used to be active.         if (e.Action != NotifyCollectionChangedAction.Remove) return;          var inactiveViews = e.OldItems;         foreach (var inactiveView in inactiveViews)         {             if (!ShouldKeepAlive(inactiveView))             {                 this.Region.Remove(inactiveView);             }         }     }      private static bool ShouldKeepAlive(object inactiveView)     {         IRegionMemberLifetime lifetime = GetItemOrContextLifetime(inactiveView);         if (lifetime != null)         {             return lifetime.KeepAlive;         }          RegionMemberLifetimeAttribute lifetimeAttribute = GetItemOrContextLifetimeAttribute(inactiveView);         if (lifetimeAttribute != null)         {             return lifetimeAttribute.KeepAlive;         }          return true;     } 

I was able to even step this code to see how it interacts with my application. To answer your question, if your KeepAlive property is not getting hit, then it is not being removed from the ActiveViews. Also make sure that if you are resolving your view from a container through IoC that you have not registered it as a singleton type (that you get a new instance each time it is resolved). The attribute/interface will only remove it completely from the region, not guarantee you get a fresh instance.

by : Alanhttp://stackoverflow.com/users/1240662




No comments:

Post a Comment

Send us your comment related to the topic mentioned on the blog