1

我有一个使用 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 挂起的方法是错误的,或者我错过了一些正确设置的步骤。

非常感谢任何帮助!

4

2 回答 2

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

In your base page object, the one that inherits from MvxStorePage, this to deserialize the stringified VMRequest. DO NOT call the base onnavigatedto method:

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

Once you've done all this, you have another problem. Mvx serializes bundles as Dictionary*string, string*, while the suspension manager that's bundled with Mvx can only deal with Dictionary*string, object*. You'll have to copy and paste the standard suspension manager that Microsoft ships into your app, and change this:

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

To this:

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

Then, you'll need to feed your altered SuspensionManager to MvX by adding the following lines to your setup.cs file:

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

Hopefully this should all be rolled into one of the future releases of Mvx so we don't have to do all these backflips.

于 2014-01-12T23:13:02.670 回答
0

我猜这不是您使用中的错误-而是“标准”的 MvvmCross 改编中的某个错误SuspensionManager-可能在正在保存的对象类型中。

MvvmCross 中的SuspensionManager代码主要基于 Windows8.0Common模板,SuspensionManager但我记得在早期开发过程中(使用各种预览版本)有很多挫败感,COMExceptions 经常返回诸如unknown error.

在实践中,Windows 8 暂停(到目前为止)在 MvvmCross 用户的优先级列表中并没有上升到非常高的位置——所以如果当前的适应需要添加或修复(尤其是当 Windows 进入 8.1 时,我不会感到惊讶) LayoutAwarePage 已被弃用)。MvvmCross 中的加载/恢复状态在许多应用程序中用于“内存中”缓存状态,但我个人没有使用它来从“挂起和关闭”终止状态恢复应用程序。

如果您的应用程序需要这种工作挂起功能并保存到磁盘/从磁盘保存,那么我相信MvxSuspensionManager和关联MvxStorePage.SaveStateBundleMvxStorePage.LoadStateBundle代码可以通过一些调试来工作,并且我相信重要的方法都已标记virtual,以便可以轻松地覆盖它们,但是......可悲的是......我相信让它们工作可能是一种令人沮丧的调试体验,包括来自“未知错误”的时刻COMException

于 2013-09-05T20:43:32.673 回答