MVVMLight 实现指定Frame控件的导航

简介: 原文:MVVMLight 实现指定Frame控件的导航 在UWP开发中,利用汉堡菜单实现导航是常见的方法。汉堡菜单导航一般都需要新建一个Frame控件,并对其进行导航,但是在MvvmLight框架默认的NavigationService中,只能对根Frame进行导航,这就需要我们实现自己的NavigationService了。
原文: MVVMLight 实现指定Frame控件的导航

在UWP开发中,利用汉堡菜单实现导航是常见的方法。汉堡菜单导航一般都需要新建一个Frame控件,并对其进行导航,但是在MvvmLight框架默认的NavigationService中,只能对根Frame进行导航,这就需要我们实现自己的NavigationService了。

MvvmLight源码简析

  • GalaSoft.MvvmLight.Views命名空间下的NavigationService继承了同命名空间下的INavigationService接口但是并没有实现。
namespace GalaSoft.MvvmLight.Views
{
     public class NavigationService : INavigationService
     {
         public const string RootPageKey = "-- ROOT --";
         public const string UnknownPageKey = "-- UNKNOWN --";
         public NavigationService();
         public string CurrentPageKey { get; }
         public void Configure(string key, Type pageType);
         public void GoBack();
         public void NavigateTo(string pageKey);
         public virtual void NavigateTo(string pageKey, object parameter);
     }
}
  • 具体的功能实现是在GalaSoft.MvvmLight.Platform命名空间下的NavigationService中,根据平台的不同有不同的实现。
  • 我们要做的就是自己实现INavigationService并自己定义导航的Frame控件

实现自己的NavigationService

很奇怪,官方公布源码的那个网站上没有找到Win10平台的Platform源码,所以我就把Win8.1的NavigationService实现复制下来,经测试能正常用。

  • 在public virtual void NavigateTo(string pageKey, object parameter)方法下,我们可以看到这样一行代码:
    var frame = ((Frame)Window.Current.Content);

    这个语句就定义了用来导航的Frame控件(不止这个方法中有,另外2个方法中也有类似的语句)。

  • 我们把这几个地方的frame变量值设置成自己的Frame控件就可以了。
  • 我的修改方法:

    • 我的Frame控件是放在MainPage中的,主要是为了实现汉堡菜单导航,我想大部分有这种需求的人都是为了实现类似的导航吧。

      1. 首先在MainPage.xaml.cs里面加入一个MainPage类型的静态Public变量
      2. 然后再构造函数中给变量赋值为this
      3. 还要给自己的Frame控件写一个属性来获取它

        public static MainPage MPage;   // 1.
        
        public Frame MyFrame            // 3.
        {
            get
            {
                return ContentFrame;    //ContentFrame是xaml中定义的Frame控件的名字
            }
        }
        
        public MainPage()
        {
            InitializeComponent();
        
            SystemNavigationManager.GetForCurrentView().BackRequested += SystemNavigationManagerBackRequested;
        
            Loaded += (s, e) =>
            {
                Vm.RunClock();
            };
        
            MPage = this;               // 2.
        }
      4. 然后就可以在自己的NavigationService里面使用自己的Frame了。

        //var frame = ((Frame)Window.Current.Content);    // 之前的语句
        var frame = MainPage.MPage.MyFrame;               // 自己写的新语句

        这样我们就把NavigationService的导航Frame设置成了MainPage里面的ContentFrame控件。

  • 不过我这个方法还不是最优的,因为这样写就把MainPage和NavigationService直接联系起来了,增加了耦合性。我看到WPF中可以通过下面这个方法来获取指定名字的Frame控件,不过在UWP里面没有这个方法。
    var frame = GetDescendantFromName(Application.Current.MainWindow, "MainFrame") as Frame;

如果谁有更好的办法的话麻烦在评论里面告诉我,万分感谢。

效果图

第一页

第二页

MyNavigationService代码

    using GalaSoft.MvvmLight.Views;
    using Mvvm_HutHelper.View;
    using System;
    using System.Collections.Generic;
    using System.Linq;

    namespace Mvvm_HutHelper.Model
    {
        class MyNavigationService : INavigationService
        {
            /// <summary>
            /// The key that is returned by the <see cref="CurrentPageKey"/> property
            /// when the current Page is the root page.
            /// </summary>
            public const string RootPageKey = "-- ROOT --";

            /// <summary>
            /// The key that is returned by the <see cref="CurrentPageKey"/> property
            /// when the current Page is not found.
            /// This can be the case when the navigation wasn't managed by this NavigationService,
            /// for example when it is directly triggered in the code behind, and the
            /// NavigationService was not configured for this page type.
            /// </summary>
            public const string UnknownPageKey = "-- UNKNOWN --";

            private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();

            /// <summary>
            /// The key corresponding to the currently displayed page.
            /// </summary>
            public string CurrentPageKey
            {
                get
                {
                    lock (_pagesByKey)
                    {
                        //var frame = ((Frame)Window.Current.Content);
                        var frame = MainPage.MPage.MyFrame;

                        if (frame.BackStackDepth == 0)
                        {
                            return RootPageKey;
                        }

                        if (frame.Content == null)
                        {
                            return UnknownPageKey;
                        }

                        var currentType = frame.Content.GetType();

                        if (_pagesByKey.All(p => p.Value != currentType))
                        {
                            return UnknownPageKey;
                        }

                        var item = _pagesByKey.FirstOrDefault(
                            i => i.Value == currentType);

                        return item.Key;
                    }
                }
            }

            /// <summary>
            /// If possible, discards the current page and displays the previous page
            /// on the navigation stack.
            /// </summary>
            public void GoBack()
            {
                //var frame = ((Frame)Window.Current.Content);
                var frame = MainPage.MPage.MyFrame;

                if (frame.CanGoBack)
                {
                    frame.GoBack();
                }
            }

            /// <summary>
            /// Displays a new page corresponding to the given key. 
            /// Make sure to call the <see cref="Configure"/>
            /// method first.
            /// </summary>
            /// <param name="pageKey">The key corresponding to the page
            /// that should be displayed.</param>
            /// <exception cref="ArgumentException">When this method is called for 
            /// a key that has not been configured earlier.</exception>
            public void NavigateTo(string pageKey)
            {
                NavigateTo(pageKey, null);
            }

            /// <summary>
            /// Displays a new page corresponding to the given key,
            /// and passes a parameter to the new page.
            /// Make sure to call the <see cref="Configure"/>
            /// method first.
            /// </summary>
            /// <param name="pageKey">The key corresponding to the page
            /// that should be displayed.</param>
            /// <param name="parameter">The parameter that should be passed
            /// to the new page.</param>
            /// <exception cref="ArgumentException">When this method is called for 
            /// a key that has not been configured earlier.</exception>
            public virtual void NavigateTo(string pageKey, object parameter)
            {
                lock (_pagesByKey)
                {
                    if (!_pagesByKey.ContainsKey(pageKey))
                    {
                        throw new ArgumentException(
                            string.Format(
                                "No such page: {0}. Did you forget to call NavigationService.Configure?",
                                pageKey),
                            "pageKey");
                    }

                    //var frame = ((Frame)Window.Current.Content);    // 这句设置导航时用到的Frame控件为根Frame
                    var frame = MainPage.MPage.MyFrame;

                    frame.Navigate(_pagesByKey[pageKey], parameter);
                }
            }

            /// <summary>
            /// Adds a key/page pair to the navigation service.
            /// </summary>
            /// <param name="key">The key that will be used later
            /// in the <see cref="NavigateTo(string)"/> or <see cref="NavigateTo(string, object)"/> methods.</param>
            /// <param name="pageType">The type of the page corresponding to the key.</param>
            public void Configure(string key, Type pageType)
            {
                lock (_pagesByKey)
                {
                    if (_pagesByKey.ContainsKey(key))
                    {
                        throw new ArgumentException("This key is already used: " + key);
                    }

                    if (_pagesByKey.Any(p => p.Value == pageType))
                    {
                        throw new ArgumentException(
                            "This type is already configured with key " + _pagesByKey.First(p => p.Value == pageType).Key);
                    }

                    _pagesByKey.Add(
                        key,
                        pageType);
                }
            }
        }
    }

参考资料

MVVM Light 5.0: How to use the Navigation service

MvvmLight SourceCode

目录
相关文章
|
5月前
MFC基本控件4-列表框控件List Box
今天和大家分享一下列表框控件的几个使用方法, 有些基本操作比如实例化对象,继承类的创建相信大家都已经灰了, 不会的可以看第一二篇文章。
|
8月前
|
缓存 数据可视化 C#
WPF技术之Frame控件
WPF (Windows Presentation Foundation) Frame是WPF中的一个控件,它在应用程序中提供了一个容器,用于加载和显示其他页面或用户界面元素。
1091 0
|
API Windows 容器
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(上)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件
161 0
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(上)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件(下)
MFC应用程序——标签控件_IP控件_时间控件_List Control控件_Tree Control控件_命令按钮_列表框_组合框_图片_滚动控件
139 0
|
Web App开发 索引
Qt之QTableView显示富文本
简述 对于QTableView中的显示,我们前面介绍过很多种,其中包括:文本、进度条、复选框等,今天我们介绍一下关于富文本的显示。 可能绝大多数小伙伴会通过QAbstractTableModel中的data来实现,可是现实告诉我们,那是行不通的,那么我们如何去显示呢?请看正文。 简述 效果 源码 分析 效果 源码 下面我们使用QAbstrac
977 0
Qt-QML-Repeater-导航条
上篇文章中,我写了一个自己的Button,也就是美化了一下QML自带的Button
247 0
Qt-QML-Repeater-导航条
|
C# 开发者
[UWP]新控件ColorPicker
原文:[UWP]新控件ColorPicker 1. 前言 Fall Creators Update中提供了一个新得ColorPicker控件,解决了以前选择颜色只能用Combo Box的窘境。 2. 一个简单的例子 如上所示,ColorPiker可以通过在光谱或色轮上拖动滑块,或者在RGB/HSV及十六进制的TextBox中直接输入颜色的数值改变Color属性。
1018 0
|
C# Windows
WPF实现炫酷Loading控件
原文:WPF实现炫酷Loading控件 Win8系统的Loading效果还是很不错的,网上也有人用CSS3等技术实现,研究了一下,并打算用WPF自定义一个Loading控件实现类似的效果,并可以让用户对Loading的颗粒(Particle)背景颜色进行自定义,话不多说,直接上代码: 1、用VS2...
1238 0

热门文章

最新文章