Emm*_* BV 5 c# xaml mvvm-light win-universal-app
我在我的新Windows 10通用应用程序C#/ XAML上遇到以下错误:
GalaSoft.MvvmLight.Platform.dll中出现类型'System.InvalidCastException'的例外,但未在用户代码中处理.附加信息:无法将类型''的对象强制转换为'Windows.UI.Xaml.Controls.Frame'.
在我的一个页面视图模型中的以下导航命令中:
_navigationService.NavigateTo(ViewModelLocator.MedicineBoxPageKey);
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用汉堡包菜单样式导航(请参阅此示例).应用程序由Microsoft提供如何执行此操作的示例):
1-在我的所有页面中共享一个方便的解决方案.上面提到的示例使用AppShell Page作为应用程序的根而不是Frame,它封装了导航菜单和后退按钮的某些行为.那将是理想的.
2-使用MVVM-Light导航服务可以方便地处理视图模型中的所有导航.
以下是App.xml.Cs如何初始化shell页面onLaunched:
AppShell shell = Window.Current.Content as AppShell;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (shell == null)
{
// Create a a AppShell to act as the navigation context and navigate to the first page
shell = new AppShell();
// Set the default language
shell.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
shell.AppFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
}
// Place our app shell in the current Window
Window.Current.Content = shell;
if (shell.AppFrame.Content == null)
{
// When the navigation stack isn't restored, navigate to the first page
// suppressing the initial entrance animation.
shell.AppFrame.Navigate(typeof(MedicinesStorePage), e.Arguments, new Windows.UI.Xaml.Media.Animation.SuppressNavigationTransitionInfo());
}
// Ensure the current window is active
Window.Current.Activate();
Run Code Online (Sandbox Code Playgroud)
这是AppShell类定义:
public sealed partial class AppShell : Page
{
public static AppShell Current = null;
public AppShell()
{
this.InitializeComponent();
}
}
Run Code Online (Sandbox Code Playgroud)
从我到目前为止所尝试的,mvvm-light导航服务仅在使用Frame作为应用程序的根并注意页面时才起作用(否则我们会得到这个转换错误).但是,使用Frame似乎不是一个选项,因为示例应用程序将其放置:
使用Page作为应用程序的根目录可以提供设计时体验,并确保在Mobile上运行时,应用程序内容不会显示在系统的StatusBar下,默认情况下可以使用透明背景显示.如果它们出现在设备上,它还会考虑软件导航按钮的存在.应用可以通过切换到UseCoreWindow来选择退出.
我还尝试从mvvm-light导航服务覆盖navigationTo方法,但是在我能够捕获它之前,这个bug似乎已经发生了.
有没有人有解决方案使用mvvm-light导航服务和shell页面作为app root(管理汉堡包菜单等)?
非常感谢!
我和Laurent Bugnion谈过,他建议我实施自己的导航服务来处理导航.为此,我创建了一个实现MVVM Light的INavigationService接口的PageNavigationService.
public class PageNavigationService : 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 = ((AppShell) Window.Current.Content).AppFrame;
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);
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 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 shell = ((AppShell) Window.Current.Content);
shell.AppFrame.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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上它是他实施的副本.但是,不是解析为Frame,而是解析为AppShell并使用AppFrame属性进行导航.
我把它放到我的ViewModelLocator.代替:
var navigationService = new NavigationService();
Run Code Online (Sandbox Code Playgroud)
我会用:
var navigationService = new PageNavigationService();
Run Code Online (Sandbox Code Playgroud)
编辑:我注意到在您使用新导航服务导航后使用反向键时NavMenuListView中存在一个excpetion,因为所选项目为null.我通过调整SetSelectedItem方法并在强制转换后在for循环中添加nullcheck来修复它:
public void SetSelectedItem(ListViewItem item)
{
var index = -1;
if (item != null)
{
index = IndexFromContainer(item);
}
for (var i = 0; i < Items.Count; i++)
{
var lvi = (ListViewItem) ContainerFromIndex(i);
if(lvi == null) continue;
if (i != index)
{
lvi.IsSelected = false;
}
else if (i == index)
{
lvi.IsSelected = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但可能有一个比这更优雅的解决方案.
| 归档时间: |
|
| 查看次数: |
1449 次 |
| 最近记录: |