无法转换类型页的对象键入“Windows.UI.Xaml.Controls.Frame”时使用MVVM光导航服务赢得10个通用的应用程序 [英] Unable to cast object of type Page to type 'Windows.UI.Xaml.Controls.Frame' when using mvvm-light navigation service in a win 10 universal app

查看:320
本文介绍了无法转换类型页的对象键入“Windows.UI.Xaml.Controls.Frame”时使用MVVM光导航服务赢得10个通用的应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我米打在我的新窗口10个通用的应用程序C#/ XAML以下错误:

I m hitting the following error on my new windows 10 universal app C#/XAML:

''类型的异常出现在GalaSoft .MvvmLight.Platform.dll但在用户代码
没有处理其他信息:无法转换类型的对象键入Windows.UI.Xaml.Controls.Frame

在下面的导航命令在我的网页浏览模式之一:

on the following navigating command in one of my page's view model:

 _navigationService.NavigateTo(ViewModelLocator.MedicineBoxPageKey);



我想有一个汉堡包的菜单式的导航(见的此示例)。应用由微软在如何做到这一点的例子)为:

I am trying to have a hamburger menu style navigation (see this sample). app by Microsoft on an example of how to do this) to:

1 - 有在我的所有网页共享的便捷的解决方案。上述示例使用AppShell页的应用程序,而不是一个帧的根,它封装了导航菜单和返回按钮的一些行为。这将是理想的。

1- have a convenient solution shared across all my pages. The sample mentioned above uses an AppShell Page as the root of the app instead of a Frame, that encapsulates the navigation menu and some behavior of the back button. That would be ideal.

2 - 使用MVVM光强的导航服务,从我的观点方便模型处理所有的导航。

2- Use the MVVM-Light navigation service to handle all the navigation from my view model conveniently.

下面是如何App.xml.Cs初始化onLaunched壳页面:

Here is how the App.xml.Cs initializes the shell page 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();



这里是AppShell类的定义:

And here is the AppShell class definition:

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

        public AppShell()
        {
            this.InitializeComponent();
         }
     }

这是我到目前为止试过了,mvvm-光导航服务只适用于当帧使用应用程序的根目录,并注意页面(否则我们得到这个错误铸造)。然而使用框架
似乎没有成为一个选项,要么因为作为示例应用程序所指出的:

From what I have tried so far, the mvvm-light navigation service only works when a Frame is used a root of the app and note a Page (otherwise we get this casting bug). However using a Frame does not seem to be a option either since as the sample app puts it:

使用页面作为该应用的根提供了设计时体验以及确保
,当它在手机上运行的应用内容下的系统状态栏默认情况下是带有透明背景的可视
将不会出现。如果它们出现在设备上,也将考虑到的软件
导航按钮的存在。应用程序可以选择不通过切换到UseCoreWindow。

Using a Page as the root for the app provides a design time experience as well as ensures that when it runs on Mobile the app content won't appear under the system's StatusBar which is visible by default with a transparent background. It will also take into account the presence of software navigation buttons if they appear on a device. An app can opt-out by switching to UseCoreWindow.

我也试图将覆盖从MVVM光导航服务的navigationTo方法,但这个错误似乎之前,我可以抓住它发生。

I also tried to overide the navigationTo method from the mvvm-light navigation service but the bug seems to occur before I could catch it.

有没有人有一个解决方案中使用的MVVM光导航服务和外壳的页面,作为应用程序根目录(管理汉堡包菜单,等等)?

Does anyone has a solution to use the mvvm-light navigation service and a shell page as the app root (that manages the hamburger menu, etc.)?

非常感谢!

推荐答案

我跟洛朗比尼翁和他推荐我到谁处理导航实现我自己的导航服务。为此,我提出谁实现MVVM光的INavigationService接口PageNavigationService。

I talked to Laurent Bugnion and he recommended me to implemented my own navigation service who handles the navigation. For this I made a PageNavigationService who implements the INavigationService Interface of MVVM Light.

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);
        }
    }
}



Basicly这是一份其实现。但是,而不是解析到一个框架我分析到AppShell并使用AppFrame属性进行导航。

Basicly it's a copy of his implementation. But instead of parsing to a Frame I parse to an AppShell and use the AppFrame Property to navigate.

我把这个给我ViewModelLocator。相反的:

I put this to my ViewModelLocator. Instead of:

var navigationService = new NavigationService();



我只用:

I will just use:

var navigationService = new PageNavigationService();



编辑:我注意到,有一个在NavMenuListView一个错误时抛出当您使用backkey您导航后因为所选择的项目,新的NavigationService为空。

I Noticed that there is an excpetion in the NavMenuListView when you use the backkey after you navigated with the new navigationservice since the selected item is null. I fixed it with adjusting the SetSelectedItem Method and adding a nullcheck in the for loop after the cast:

    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;
            }
        }
    }



但有可能是一个比较优雅的解决方案莫过于此。

But there might be a more elegant solution than this.

这篇关于无法转换类型页的对象键入“Windows.UI.Xaml.Controls.Frame”时使用MVVM光导航服务赢得10个通用的应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆