挂起Windows应用商店应用:调用MvxSuspensionManager.SaveAsync()时出错

时间:2013-09-05 12:23:46

标签: c# windows-runtime mvvmcross

我有一个使用MvvmCross的WinRT应用程序,我想存储当前的会话状态。

在App.xaml.cs的OnLaunch方法中,我使用暂停管理器注册了我的应用程序的内容框架:

...
var setup = new Setup(_contentFrame);
setup.Initialize();

var suspensionManager = Mvx.GetSingleton<IMvxSuspensionManager>() as MvxSuspensionManager;
suspensionManager.RegisterFrame(_contentFrame, "FrameNav");
...         

每当我暂停应用程序并在OnSuspending事件处理程序中运行代码

var suspensionManager = Mvx.GetSingleton<IMvxSuspensionManager>() as MvxSuspensionManager;

await suspensionManager.SaveAsync();

我收到以下异常。

Cirrious.MvvmCross.WindowsStore.Views.Suspension.MvxSuspensionManagerException "MvxSuspensionManager failed"
at Cirrious.MvvmCross.WindowsStore.Views.Suspension.MvxSuspensionManager.<SaveAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at ****App.xaml.cs:line 129
System.Runtime.InteropServices.COMException "Unbekannter Fehler
"
at Windows.UI.Xaml.Controls.Frame.GetNavigationState()
at Cirrious.MvvmCross.WindowsStore.Views.Suspension.MvxSuspensionManager.SaveFrameNavigationState(Frame frame)
at Cirrious.MvvmCross.WindowsStore.Views.Suspension.MvxSuspensionManager.<SaveAsync>d__0.MoveNext()

我很确定我可以将异常根缩小到对

的WinRT API调用
Frame.GetNavigationState();

由MvxSuspensionManager执行。当我直接调用此函数时,它将失败并出现相同的错误。

我知道如果将非复杂类型用作导航参数,则只能序列化WinRT帧导航堆栈。但即使我暂停在第一页,我的应用程序也会崩溃。

也许我使用MvvmCross挂起的方法是错误的,或者我错过了一些正确设置的步骤。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

有两个问题导致暂停管理器无效。正如您所说,MvX使用复杂(ViewModelRequests)对象而不是字符串进行导航。你可以通过创建自己的ViewPresenter来解决这个问题,它应该是这样的:

public class CustomViewPresenter : MvxStoreViewPresenter {
    //XXX: Holding a ref here because base class's ref to the frame is for some reason private.
    private Frame _curFrame;
    public CustomViewPresenter(Frame RootFrame) : base(RootFrame) {
        _curFrame = RootFrame;
    }

    public override void Show(MvxViewModelRequest request) {
        try {
            var requestTranslator = Mvx.Resolve<IMvxViewsContainer>();
            var viewType = requestTranslator.GetViewType(request.ViewModelType);

            var converter = Mvx.Resolve<IMvxNavigationSerializer>();
            var requestText = converter.Serializer.SerializeObject(request);

            _curFrame.Navigate(viewType, requestText);
        } catch (Exception exception) {
            MvxTrace.Trace("Error seen during navigation request to {0} - error {1}", request.ViewModelType.Name,
                           exception.ToString());
        }
    }
}

在基页对象中,从MvxStorePage继承的对象,用于反序列化字符串化的VMRequest。不要将基地打电话给方法:

    protected override void OnNavigatedTo(NavigationEventArgs e) {
        var reqData = (string)e.Parameter;

        var converter = Mvx.Resolve<IMvxNavigationSerializer>();
        var req = converter.Serializer.DeserializeObject<MvxViewModelRequest>(reqData);

        this.OnViewCreate(req, () => LoadStateBundle(e));
    }

完成所有这些后,您还有另一个问题。 Mvx将bundle序列化为Dictionary * string,string *,而与Mvx捆绑在一起的暂停管理器只能处理Dictionary * string,object *。您必须将Microsoft发布的标准暂停管理器复制并粘贴到您的应用程序中,然后更改:

private readonly List<Type> _knownTypes = new List<Type>(); 

对此:

private readonly List<Type> _knownTypes = new List<Type>() { typeof(Dictionary<string, string>) };

然后,您需要通过在setup.cs文件中添加以下行来将修改后的SuspensionManager提供给MvX:

    protected override Cirrious.MvvmCross.WindowsStore.Views.Suspension.IMvxSuspensionManager CreateSuspensionManager() {
        return new MyFixedSuspensionManager();
    }

希望这一切都应该归入未来的Mvx版本之一,这样我们就不需要做所有这些后空翻。

答案 1 :(得分:0)

我猜这不是你使用中的错误 - 而是在'标准'SuspensionManager的MvvmCross适应中的某个地方 - 可能是在保存的对象类型中。

MvvmCross中的SuspensionManager代码主要基于Common的Windows8.0 SuspensionManager模板 - 但我记得在早期开发过程中有很多挫折(使用各种预览使用COMException s经常返回unknown error这样无用的消息。

实际上,Windows 8暂停还没有(到目前为止)在MvvmCross用户的优先级列表中上升得非常高 - 所以如果当前适应需要增加或修复,我不会感到惊讶(特别是当Windows移动时)到8.1,其中不推荐使用LayoutAwarePage)。 MvvmCross中的加载/恢复状态在许多应用程序中用于“内存中”缓存状态,但我个人并未使用它来从“挂起和关闭”终止状态恢复应用程序。

如果您的应用需要此工作暂停功能并保存到磁盘或从磁盘保存,那么我相信MvxSuspensionManager以及相关的MvxStorePage.SaveStateBundleMvxStorePage.LoadStateBundle代码可以是通过一些调试工作,我相信重要的方法都标记为virtual,以便它们可以轻松覆盖,但是......遗憾的是......我相信让它们工作可能会令人沮丧的调试体验包括来自COMException

的'未知错误'的时刻