我有一个使用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挂起的方法是错误的,或者我错过了一些正确设置的步骤。
非常感谢任何帮助!
答案 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.SaveStateBundle
和MvxStorePage.LoadStateBundle
代码可以是通过一些调试工作,我相信重要的方法都标记为virtual
,以便它们可以轻松覆盖,但是......遗憾的是......我相信让它们工作可能会令人沮丧的调试体验包括来自COMException