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中的,主要是为了实现汉堡菜单导航,我想大部分有这种需求的人都是为了实现类似的导航吧。
- 首先在MainPage.xaml.cs里面加入一个MainPage类型的静态Public变量
- 然后再构造函数中给变量赋值为this
还要给自己的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.
}然后就可以在自己的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);
}
}
}
}
参考资料
MVVMLight 实现指定Frame控件的导航的更多相关文章
- 背水一战 Windows 10 (41) - 控件(导航类): Frame
[源码下载] 背水一战 Windows 10 (41) - 控件(导航类): Frame 作者:webabcd 介绍背水一战 Windows 10 之 控件(导航类) Frame 示例Controls ...
- 背水一战 Windows 10 (42) - 控件(导航类): Frame 动画
[源码下载] 背水一战 Windows 10 (42) - 控件(导航类): Frame 动画 作者:webabcd 介绍背水一战 Windows 10 之 控件(导航类) Frame 动画 示例An ...
- 使用Frame控件设计Silverlight的导航
这里所说的导航其实就是在Silverlight的页面之间前进后退以及跳转.通过Frame控件配合后台NavigationService类可以很容易的做到页面之间的导航. 这就是工具箱中的Frame控件 ...
- 背水一战 Windows 10 (40) - 控件(导航类): AppBar, CommandBar
[源码下载] 背水一战 Windows 10 (40) - 控件(导航类): AppBar, CommandBar 作者:webabcd 介绍背水一战 Windows 10 之 控件(导航类) App ...
- .net验证控件,导航控件
一.客户端验证(用户体验,减少服务器端压力) 二.服务器端验证(防止恶意攻击,客户端js很容易被绕过) 验证控件:RequiredFieldValidator:字段必填:RangeValidator: ...
- <iOS小技巧>UIview指定设置控件圆角
一.用法: 众所周知,设置控件的圆角使用layer.cornerRadius属性即可,但是这样设置成的结果是4个边角都是圆角类型. 利用班赛尔曲线画角: //利用班赛尔曲线画角 UIB ...
- 【完全开源】百度地图Web service API C#.NET版,带地图显示控件、导航控件、POI查找控件
目录 概述 功能 如何使用 参考帮助 概述 源代码主要包含三个项目,BMap.NET.BMap.NET.WindowsForm以及BMap.NET.WinformDemo. BMap.NET 对百度地 ...
- VC++ 如何在显示对话框的时候,指定焦点控件!
很简单: 在你的CAddDlg类的OnInitDialog函数中加上你上面的代码GetDlgItem(IDC_EDIT1)->SetFocus();最后记得return FALSE; 其实,不知 ...
- C/S模式开发中如何利用WebBrowser控件制作导航窗体
原文:C/S模式开发中如何利用WebBrowser控件制作导航窗体 转自: CSDN 相信不少同学们都做过MIS系统的开发,今天这里不讨论B/S模式开发的问题.来谈谈winform开发.用过市面上常见 ...
随机推荐
- iOS --- UIColor中使用16进制选取颜色
iOS中的UIColor能够使用16进制来选取颜色. 预先定义例如以下: #define UIColorFromHex(s) [UIColor colorWithRed:(((s & 0xFF ...
- Ubuntu,右键->在终端中打开(apt-install,或者手动增加右键菜单)
方法一: sudo apt-get install nautilus-open-terminal 然后重启 方法二: Ubuntu中,默认右键菜单中没有“在终端中打开”.要想添加此菜单,可以在主目录中 ...
- sublime-1 sublime设置到鼠标右键
sublime-1 sublime设置到鼠标右键 一.总结 一句话总结:其实windows可以更加熟悉一点才好,毕竟用的那么多,regedit可以添加注册,也可以添加鼠标右键选项. 二.sublime ...
- vs 错误提示及解决方案
错误: 应输入";" 错误原因,宏展开出现错误:
- [Ramda] Pick and Omit Properties from Objects Using Ramda
Sometimes you just need a subset of an object. In this lesson, we'll cover how you can accomplish th ...
- [Angular] Content Projection with ng-content
For example there is tow form compoennts on the page, and what we want to do is reusing the form com ...
- 集群搭建Solr
Solr集群搭建 SolrCloud需要solr基于zookeeper部署,zookeeper是一个集群管理软件,由于SolrCloud需要由多台服务器组成.由zookeeper来进行协调管理.Zoo ...
- Hibernate中的配置文件
Hibernate中配置文件 主配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE h ...
- ORACLE中死锁
ORACLE中死锁的知识点总结 死锁的概念 什么是死锁呢? 其实我们生活中也有很多类似死锁的例子. 我先举一个生活中的例子:过年回家,父亲买了一把水弹枪,儿子和侄子争抢着要先玩,谁也不让谁,拆开包 ...
- NOIP模拟 MST - 类次小生成树
题目大意: 给一张无向图,可以将图中权值为v的边修改为k-v,求修改后的最小生成树边权和. 题目分析: 最小生成树的环切定理:任何非树边一定比对应树链上的所有边权值要大.否则我们可以将链上最大的树边删 ...