What is the best way to recreate views?

Topics: Prism v4 - Silverlight 4
Apr 24, 2011 at 7:26 PM
Edited Apr 24, 2011 at 7:53 PM

I have some questions:

1) I'd like to know what is the best way to recreate views whenever they are requested(MEF is used). I suppose it could be implemented by doing the following:

  • using view injection
  • getting the view to be injected by requesting  ExportFactory<ViewType> property(it's done everytime when the view is requested)
  • applying attribute [RegionMemberLifetime(KeepAlive = false]

Are there some better ways to it?

2) Let there are two modules. Every module registers some view in the same region. The first region is immediately loaded(and its view is immediately displayed ), other - on demand.

 When I navigate to the second view from the first view and then try to go back by using NavigationContext.NavigationService.Journal.GoBack(), it doesn't work.

And I can't understand why?

Thanks in advance.

 

Apr 25, 2011 at 7:59 AM

Andrew,

You could probably try adding the PartCreationPolicy for your view and set it to NonShared. That way the view will be created each time you request it.

Cheers.

Ganesh

Apr 25, 2011 at 11:23 AM
Edited Apr 25, 2011 at 11:24 AM

Thanks for reply.

Using  [PartCreationPolicy(CreationPolicy.NonShared)] was the first thing I tried, but it didn't work(if I set the breakpoint in the ctor, it is hit only once).

What wrong might I have done ?

And what about the 2nd question? ;)

 

Apr 25, 2011 at 12:25 PM

Are you implementing INavigationAware on your view model? If yes then try this in the OnNavigatedFrom

public void OnNavigatedFrom(NavigationContext navigationContext)
{
    var region = _regionManager.Regions["MyRegion"];
    if (region is SingleActiveRegion)
    {
        var activeView = region.ActiveViews.SingleOrDefault();
        if (activeView != null) region.Deactivate(activeView);
    }
}

You could put this logic in a viewmodel base or something and call it on the OnNavigatedFrom. This apparently is by design and doing the above solves the problem. Let me know if this helped.

Cheers,

Ganesh

 

 

Apr 25, 2011 at 1:37 PM

It didn't help...

It's my Module class

[ModuleExport(typeof(ModuleInitializer))]
public class ModuleInitializer : IModule
{
        private readonly IRegionManager _regionManager;

        [ImportingConstructor]
        public ModuleInitializer(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }
       
        public void Initialize()
        {
            _regionManager.RegisterViewWithRegion("MainRegion", typeof (View));            
        }   
 }

 
and the view:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class View : UserControl
{
        [ImportingConstructor]
        public View(ViewModel viewModel)
        {
            InitializeComponent();
            DataContext = viewModel;
        }          
}


viewmodel:

 [Export]
 [PartCreationPolicy(CreationPolicy.NonShared)]
 public class ViewModelB : NotificationObject, INavigationAware, 
 {
        private readonly IRegionManager _regionManager;
      
        public ViewModel()
        {
           
        }

        #region Implementation of INavigationAware
        ....
        #endregion
}

Maybe, there is something wrong with the code?


Apr 25, 2011 at 1:52 PM
Edited Apr 25, 2011 at 4:45 PM
Did you put the code I gave in you inavigationaware implementation? That solution works with me. With one difference being I don't do a registerviewwithregion. I use the region.requestnavigate to load modules in my region.

 


From: Andrew123 <notifications@codeplex.com>
To: Shivshankar, Ganesh (IT/IN)
Sent: Mon Apr 25 18:07:48 2011
Subject: Re: What is the best way to recreate views? [CompositeWPF:255110]

From: Andrew123

It didn't help...

It's my Module class

 

[ModuleExport(typeof(ModuleInitializer))]
public class ModuleInitializer : IModule
{
        private readonly IRegionManager _regionManager;

        [ImportingConstructor]
        public ModuleInitializer(IRegionManager regionManager)
        {
            _regionManager = regionManager;
        }
       
        public void Initialize()
        {
            _regionManager.RegisterViewWithRegion("MainRegion", typeof (View));            
        }   
 }

and the view:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class View : UserControl
{
        [ImportingConstructor]
        public View(ViewModel viewModel)
        {
            InitializeComponent();
            DataContext = viewModel;
        }          
}


viewmodel:

 [Export]
 [PartCreationPolicy(CreationPolicy.NonShared)]
 public class ViewModelB : NotificationObject, INavigationAware, 
 {
        private readonly IRegionManager _regionManager;
      
        public ViewModel()
        {
           
        }

        #region Implementation of INavigationAware
        ....
        #endregion
}

Maybe, there is something wrong with the code?

 

 

 

Apr 25, 2011 at 4:39 PM

At long last, I've found what was wrong!

Earlier, I thought that views had to be registered in a region using view injection or discovery even if navigation is implemented using RequestNavigate approach. :)

After I took _regionManager.RegisterViewWithRegion("MainRegion", typeof(View)) away, and invoking _regionManager.RequestNavigate("MainRegion", "View"), I got error 'Cannot create navigation target 'View''. Then I decided to use the full type name of the view in RequestNavigate and finally I got it working!!!

But now I can't understand why navigation worked earlier when invoking RequestNavigate with short name of the view, that is, _regionManager.RequestNavigate("MainRegion", "View")  ( "View" wasn't the export's contract) ?

Apr 25, 2011 at 4:50 PM

Glad you could resolve it.

With RegisterViewWithRegion you are giving the type to it. It needs a contract name when using RequestNavigate.

[Export("MyView")]

By default it takes the type name as the export name if contract is not specified. You can check that by just injection the AggregateCatalog in your view and inspecting the Parts property in it.

Did you have to put the logic I gave in the OnNavigatedTo method?

Apr 25, 2011 at 5:35 PM
Edited Apr 25, 2011 at 5:36 PM

You're right - when using RegisterViewWithRegion , the contract name is simply the short name of the view(I thought the contract name was the full name of the view, hence I was suprised why it worked).

So, now everything is ok.

As for putting the additional logic into OnNavigatedFrom method, it's apparently unnecessary for now.

Thanks again for your very valuable replies and answers!!!

 

Apr 26, 2011 at 4:02 AM

Glad I could help !

Oct 2, 2012 at 5:09 PM

Also get the "Cannot Create Navigation Target" NavigationResult .. after wasting a good part of my day, seems INavigationAware Constructor would not allow parameter. 

After removing the parameter in the constructor it works as expected.