Lazy loading views

Topics: Prism v4 - Silverlight 4, Prism v4 - WPF 4
Oct 17, 2011 at 5:11 PM

Hello!

I've got many views registered under the same region (this can't be changed). I need to instantiate view only when they are required. Currently I'm using this ugly code to achieve this:

using System.Collections.Generic;
using Common;
using Common.Events;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Unity;
using OnAgile.Views;

namespace OnAgile.Controllers
{
    public class MainController : ControllerBase
    {
        public MainController(IUnityContainer container, IEventAggregator eventAggregator, IRegionManager regionManager)
            : base(container, eventAggregator, regionManager)
        {
            InitViews();
            DisplayView(ViewNames.LoginView);

            EventAggregator.GetEvent<SwitchViewEvent>().Subscribe(OnSwitchViewEvent, true);
        }

        private void InitViews()
        {
            viewsMap = new Dictionary<string, object>();
            viewsMap[ViewNames.LoginView] = null;
            viewsMap[ViewNames.RegisterView] = null;
            viewsMap[ViewNames.RegisterView] = null;
        }

        private void DisplayView(string viewName)
        {
            IRegion mainRegion = GetMainRegion();

            object view = null;

            if (viewsMap[viewName] == null)
            {
                //can't use switch here
                if (viewName == ViewNames.LoginView)
                    view = Container.Resolve<LoginView>();
                else if (viewName == ViewNames.RegisterView)
                    view = Container.Resolve<RegistrationView>();
                else if (viewName == ViewNames.ActivateView)
                    view = Container.Resolve<ActivationView>();

                if (view != null)
                {
                    viewsMap[viewName] = view;
                    mainRegion.Add(view, viewName);
                }
            }

            view = mainRegion.GetView(viewName);

            if (view != null)
                mainRegion.Activate(view);
        }

        private IRegion GetMainRegion()
        {
            return RegionManager.Regions[RegionNames.MainRegion];
        }

        public void OnSwitchViewEvent(string viewName)
        {
            if (viewsMap.ContainsKey(viewName))
                DisplayView(viewName);
        }

        private Dictionary<string, object> viewsMap;
    }
}

As you can see I'm holding dictionary and resolve views only when needed (when composite event SwitchViewEvent is received). Is there any more elegant approach to do what I want?

PS. RegisterViewWithRegion( delegate ) also resolves views immediately :(

Developer
Oct 17, 2011 at 8:54 PM

Hi,

The view discovery approach (that is, using the RegisterViewWithRegion method) is designed to automatically populate a region, with the corresponding registered views, when the region is available using the AutoPopulateRegionBehavior. If you need to control when a view is going to be "shown" in a region, it's recommended to use the view injection approach (that is, adding a view to a region with the Add method) or use navigation instead.

However, if you cannot change this, you might need to implement a custom method to control the views registered in the region and when they are going be injected. For example, a possible approach could be to create your own implementation of the AutoPopulateRegionBehavior (which is the one that creates and adds the registered views to the regions) so that you can control when the views will be added in the corresponding region.

Regarding the approach that you describe above, it seems to be a valid approach as the implementation details depends mostly of the requirements of your scenario and your personal preferences. However, in the case that this approach is being used with a single active region (for example a ContentControl), the views seems to be added and activated but never removed from the region, which could cause an undesired memory leak. To avoid this you could remove the views in the region before adding the new one or use navigation instead. Again, these recommendations only applies to a single active region and might not be required if the region must contain more than one view, like a TabControl or a ListBox.

Also, you can find more information in the following links:

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini