This project is read-only.

Navigation

Interfaces

Navigation engine simplifies the way how your application navigates between pages. It provides the following interfaces:

  • IPage – represents a type of page which is used by mapping for navigation

 

namespace PhoneCore.Framework.Navigation
{
    /// <summary>
    /// Represetns a type of page which is used by navigation subsystem
    /// </summary>
    public interface IPage: IEquatable<IPage>
    {
        string Name { get; }
    }
}

 

  • INavigationService – defines the behavior of navigation engine

 

namespace PhoneCore.Framework.Navigation
{
    /// <summary>
    /// Represents navigation service
    /// </summary>
    public interface INavigationService
    {
        /// <summary>
        /// Navigating event
        /// </summary>
        event NavigatingCancelEventHandler Navigating;
        
        /// <summary>
        /// Navigates to uri
        /// </summary>
        /// <param name="pageUri"></param>
        void NavigateTo(Uri pageUri);

        /// <summary>
        /// Navigates to uri and passes parameters
        /// </summary>
        /// <param name="pageUri"></param>
        /// <param name="parameters"></param>
        void NavigateTo(Uri pageUri, Dictionary<string, object> parameters);

        /// <summary>
        /// Navigates using page instance in mapping
        /// </summary>
        /// <param name="type"></param>
        void NavigateTo(IPage type);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="parameters"></param>
        void NavigateTo(IPage type, Dictionary<string, object> parameters);

        /// <summary>
        /// Goes back
        /// </summary>
        void GoBack();
    }
} 

 

  • IPageResolver – the class which implements this interface should return the corresponding page by its type

 

namespace PhoneCore.Framework.Navigation
{
    public interface IPageResolver
    {
        IPage Resolve(string name);
    }
} 

 

Let’s look how the default implementation works.

Implementation

The essential part of navigation is page mapping which is defined through configuration:

 

 <views>
    <!-- page mapping -->
    <pageMapping>
      <resolver type="SecureBox.UI.Infrastructure.PageResolver, SecureBox.UI" />
      <pages>
        <page name="Startup">
          <uri type="relative" address="/ViewPage/StartupViewPage.xaml" />
          <viewModel type="SecureBox.UI.ViewModel.StartupViewPageModel, SecureBox.UI" />
        </page>
        <page name="Library">
          <uri type="relative" address="/ViewPage/LibraryViewPage.xaml" />
          <viewModel type="SecureBox.UI.ViewModel.LibraryViewPageModel, SecureBox.UI" />
        </page>
        <page name="Password">
          <uri type="relative" address="/ViewPage/PasswordViewPage.xaml" />
          <viewModel type="SecureBox.UI.ViewModel.PasswordViewPageModel, SecureBox.UI" />
        </page>
        <page name="Account">
          <uri type="relative" address="/ViewPage/AccountViewPage.xaml" />
          <viewModel type="SecureBox.UI.ViewModel.AccountViewPageModel, SecureBox.UI" />
        </page>
        <page name="Email">
          <uri type="relative" address="/ViewPage/EmailViewPage.xaml" />
          <viewModel type="SecureBox.UI.ViewModel.EmailViewPageModel, SecureBox.UI" />
        </page> 

 

As it`s seen, each page is defined by page node:

  • name – page name which is unique. The resolver should return the page instance by this
  • uri –defines path to this page
  • viewModel – viewModel type of the page. It should implement PhoneCore.Framework.Views.IViewModel interface

Also pageMapping node contains the definition of IPageResolver type which is used for resolving pages. Now let’s focus on how mapping is implemented:

 

namespace PhoneCore.Framework.Navigation
{
    /// <summary>
    /// Represents page mapping
    /// </summary>
    public class PageMapping: IPageMapping
    {
        private readonly object _syncLock = new object();
        private Dictionary<IPage, Tuple<Uri, Lazy<IViewModel>>> _pageMapping = new Dictionary<IPage, Tuple<Uri, Lazy<IViewModel>>>();

        public PageMapping(ConfigSection config, IContainer container)
        {
            var pages = config.GetSections("pages/page");
            var resolverConfig = config.GetSection("resolver");
            IPageResolver resolver = resolverConfig.GetInstance<IPageResolver>("@type", resolverConfig, container);
            foreach (var configPage in pages)
            {
                var name = configPage.GetString("@name");
                var page = resolver.Resolve(name);
                //TODO support other types of uri
                var uri = new Uri(configPage.GetSection("uri").GetString("@address"), UriKind.Relative);
                var vmSection = configPage.GetSection("viewModel");
                lock(_syncLock)
                    _pageMapping.Add(page, new Tuple<Uri, Lazy<IViewModel>>(
                        uri,
                        new Lazy<IViewModel>(() => vmSection.GetInstance<IViewModel>("@type", vmSection, container))));
            }
        }

        public PageMapping(Dictionary<IPage, Tuple<Uri, Lazy<IViewModel>>> mapping)
        {
            _pageMapping = mapping;
        }

        /// <summary>
        /// get page uri by its type
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        public Uri GetUri(IPage page)
        {
            return _pageMapping.Single(m => m.Key.Equals(page)).Value.Item1;
        }

        /// <summary>
        /// get page's ViewModel by its type
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        public IViewModel GetViewModel(IPage page)
        {
            return _pageMapping.Single(m => m.Key.Equals(page)).Value.Item2.Value;
        }

        /// <summary>
        /// get page type by uri
        /// </summary>
        /// <param name="pageUri"></param>
        /// <returns></returns>
        public IPage GetPage(Uri pageUri)
        {
            return _pageMapping.Keys.Single(m => _pageMapping[m].Item1 == pageUri);
        }

    }
} 

 

So the constructor creates the dictionary Dictionary <IPage, Tuple<Uri, Lazy<IViewModel>>> where the key is page type and value is tuple containing “lazy” wrapper for IViewModel. It prevents from the creation of each ViewModels during PageMapping initialization.

Last edited Feb 11, 2012 at 10:22 PM by Ilya_Builuk, version 3

Comments

No comments yet.