更新时间:2022-09-22 22:45:53
在UWP开发中,利用汉堡菜单实现导航是常见的方法。汉堡菜单导航一般都需要新建一个Frame控件,并对其进行导航,但是在MvvmLight框架默认的NavigationService中,只能对根Frame进行导航,这就需要我们实现自己的NavigationService了。
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);
}
}
很奇怪,官方公布源码的那个网站上没有找到Win10平台的Platform源码,所以我就把Win8.1的NavigationService实现复制下来,经测试能正常用。
在public virtual void NavigateTo(string pageKey, object parameter)方法下,我们可以看到这样一行代码: var frame = ((Frame)Window.Current.Content);
这个语句就定义了用来导航的Frame控件(不止这个方法中有,另外2个方法中也有类似的语句)。
我的修改方法:
我的Frame控件是放在MainPage中的,主要是为了实现汉堡菜单导航,我想大部分有这种需求的人都是为了实现类似的导航吧。
还要给自己的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控件。
var frame = GetDescendantFromName(Application.Current.MainWindow, "MainFrame") as Frame;
如果谁有更好的办法的话麻烦在评论里面告诉我,万分感谢。
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);
}
}
}
}