C# 无法将Page类型的对象强制转换为';Windows.UI.Xaml.Controls.Frame';在win 10 universal应用程序中使用mvvm灯光导航服务时

C# 无法将Page类型的对象强制转换为';Windows.UI.Xaml.Controls.Frame';在win 10 universal应用程序中使用mvvm灯光导航服务时,c#,xaml,mvvm-light,win-universal-app,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.Medic

我在新的windows 10通用应用程序C#/XAML上遇到以下错误:

GalaSoft.MvvmLight.Platform.dll中发生类型为“System.InvalidCastException”的异常,但未在用户代码中处理 其他信息:无法将“”类型的对象强制转换为“Windows.UI.Xaml.Controls.Frame”类型

在“我的页面”的某个视图模型中的以下导航命令上:

 _navigationService.NavigateTo(ViewModelLocator.MedicineBoxPageKey);
我正在尝试汉堡包菜单式导航(请参阅)。Microsoft的应用程序(关于如何执行此操作的示例),以:

1-在我的所有页面上共享一个方便的解决方案。上面提到的示例使用AppShell页面作为应用程序的根,而不是框架,框架封装了导航菜单和后退按钮的一些行为。那将是理想的

2-使用MVVM Light导航服务方便地处理来自my view模型的所有导航

下面是App.xml.Cs如何初始化仅启动的shell页面:

    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();
下面是AppShell类的定义:

public sealed partial class AppShell : Page
    {
        public static AppShell Current = null;

        public AppShell()
        {
            this.InitializeComponent();
         }
     }
从我到目前为止所做的尝试来看,mvvm light navigation服务只有在一个框架被用作应用程序的根目录并记录一个页面时才起作用(否则我们就会遇到这个铸造错误)。 但是,使用框架似乎也不是一个选项,因为正如示例应用程序所说:

使用页面作为应用程序的根目录可以提供设计时体验,并确保 当它在移动设备上运行时,应用程序内容不会显示在系统的状态栏下,该状态栏是可见的 默认情况下,使用透明背景。它还将考虑软件的存在 导航按钮(如果它们出现在设备上)。应用程序可以通过切换到UseCoreWindow选择退出

我还试图从mvvm light navigation服务中覆盖navigationTo方法,但该错误似乎在我捕获它之前就出现了

是否有人有解决方案使用mvvm light导航服务和shell页面作为应用程序根目录(管理汉堡菜单等)


非常感谢

我和Laurent Bugnon谈过,他建议我实施自己的导航服务,由他负责导航。为此,我制作了一个PageNavigationService,它实现了MVVM Light的INavigationService接口

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);
        }
    }
}
我只会使用:

var navigationService = new PageNavigationService();
编辑:我注意到在使用新的navigationservice导航后使用backkey时,NavMenuListView中有一个例外,因为所选项目为空。我通过调整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;
            }
        }
    }
public void SetSelectedItem(ListViewItem项)
{
var指数=-1;
如果(项!=null)
{
索引=IndexFromContainer(项目);
}
对于(变量i=0;i

但可能还有比这更优雅的解决方案。

我认为“GoBack”方法应该是“var frame=((AppShell)Window.Current.Content).AppFrame;”而不是'var frame=((frame)Window.Current.Content);'但在其他方面,它就像一个符咒。
    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;
            }
        }
    }