挂起 Windows 应用商店应用:调用 MvxSuspensionManager.SaveAsync() 时出错
本文关键字:应用 SaveAsync 出错 MvxSuspensionManager 调用 Windows 挂起 | 更新日期: 2023-09-27 18:30:21
我有一个使用 MvvmCross 的 WinRT 应用程序,我想在其中存储当前会话状态。
在 app.xaml 的 OnLaunch 方法中.cs我向挂起管理器注册了应用程序的内容框架:
...
var setup = new Setup(_contentFrame);
setup.Initialize();
var suspensionManager = Mvx.GetSingleton<IMvxSuspensionManager>() as MvxSuspensionManager;
suspensionManager.RegisterFrame(_contentFrame, "FrameNav");
...
每当我挂起应用并在 OnSuging 事件处理程序中运行代码时
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();
由 MvxSussuspension Manager 执行。当我直接调用此函数时,它将失败并出现相同的错误。
我知道 WinRT 帧导航堆栈只有在将非复杂类型用作导航参数时才能序列化。但是即使我只是在第一页上挂起,我的应用程序也会崩溃。
也许我使用 MvvmCross 暂停的方法错误,或者我错过了一些正确设置的步骤。
任何帮助都非常感谢!
有两个问题正在禁用挂起管理器。正如您所说,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。不要调用基本 onnavigatedto 方法:
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 将捆绑包序列化为 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 文件中,将更改后的 Sussuspension Manager 提供给 MvX:
protected override Cirrious.MvvmCross.WindowsStore.Views.Suspension.IMvxSuspensionManager CreateSuspensionManager() {
return new MyFixedSuspensionManager();
}
希望这一切都应该被纳入 Mvx 的未来版本之一,这样我们就不必做所有这些后空翻。
我猜这不是您使用中的错误 - 而是"标准"SuspensionManager
的 MvvmCross 改编中的某个错误 - 可能在正在保存的对象类型中。
MvvmCross中的SuspensionManager
代码主要基于Windows8.0 Common
模板SuspensionManager
- 但我记得在早期开发过程中(使用各种预览版本)有很多挫折,COMException
经常返回诸如unknown error
之类的无用消息。
实际上,Windows 8 暂停(到目前为止)在 MvvmCross 用户的优先级列表中并没有上升到很高的位置 - 所以如果当前改编需要添加或修复,我不会感到惊讶(特别是当 Windows 进入 8.1 时,LayoutAwarePage 已被弃用)。MvvmCross 中的加载/还原状态在许多应用程序中用于"内存中"缓存状态,但我个人没有使用它来从"挂起和关闭"终止状态恢复应用程序。
如果您的应用程序需要这种工作暂停功能并保存到/从磁盘保存,那么我相信只需稍加调试即可使MvxSuspensionManager
和关联的MvxStorePage.SaveStateBundle
和MvxStorePage.LoadStateBundle
代码工作,并且我相信重要方法都标记为virtual
,以便可以轻松覆盖它们,但是......可悲的是。。。我相信让它们工作可能是一种令人沮丧的调试体验,包括来自COMException
的"未知错误"时刻