2014-01-22 11 views
0

我创建了一个基于Caliburn.Micro(alpha2)的WinRT 8.1应用程序,并且正在为它实现一个简单的状态管理机制。它所需要的只是为其两个或三个页面中的每一个保存一对名称/值对,并在恢复时恢复当前页面。所以我正在使用下面总结的战略;因为看起来CM/WinRT没有预定义的机制,所以得到任何有关这方面的社区建议都很有意思,或者这对希望像我这样的RT新手有用。 1)我定义了一个接口IHaveSimpleState),由具有一些简单状态的VM来实现以进行保存和恢复。状态由一个字典表示,其中每个值都是一个字符串,表示任何序列化的值,接口只有2个方法,一个用于将状态保存到此字典中,另一个用于从字典中恢复状态。我所有的有状态虚拟机(每个对应一个视图)都实现了这一点。在Caliburn Micro WinRT 8.1中管理简单状态:导航到之前的活动页面

2)在我应用的.cs(从Caliburn.Application派生),我创建了一个List<WeakReference<IHaveSimpleState>>保留所有的虚拟机需要国家管理的轨道:在GetInstance覆盖该实例的虚拟机(使用CM简单的容器),我添加到此列表中每个新生成的实例IHaveSimpleState

3)节约状态:在应用OnSuspending覆盖,通过所有的虚拟机我循环在此列表中,并调用其SaveState方法收集有关其状态的数据在一个共同的字典。一旦循环完成,我得到ApplicationData.Current.LocalSettings,我将这些数据复制到它的Values字典中,从而有效地保存它们。

4)恢复状态:在该应用OnResuming倍率和在OnActivated倍率(在后一种情况下,仅当args.PreviousExecutionState等于Running,即,应用程序不是由用户终止也不崩溃),I调用一个ResumeState方法循环访问列表中的所有虚拟机,并调用它们的LoadState方法从应用程序数据本地设置加载状态。

所有这些看起来都很好,我只想念一个观点:恢复当前“页面”的正确位置是什么,即告诉Caliburn导航到暂停时激活的视图后面的VM?我试图在我的ResumeState方法(nr.4)结束时这样做,但似乎为时过早,因为当我尝试导航到虚拟机时,出现异常,告诉我无法找到相应的视图。下面是该方法的相关代码:

private void ResumeState() 
{ 
    // ... state is a dictionary wrapper class with state data 

    // restore state for each tracked VM 
    foreach (WeakReference<IHaveSimpleState> reference in _statefulViewModels) 
    { 
     IHaveSimpleState stateful; 
     if (reference.TryGetTarget(out stateful)) stateful.LoadState(state); 
    } 

    // move to the page which was current when the state was saved 
    string sType = state.Get(APP_CURRENTVM_KEY, null); 
    if (sType != null) 
    { 
     // not so elegant... 
     INavigationService navigation = IoC.Get<INavigationService>(); 
     Type t = Type.GetType(sType); 
     navigation.NavigateToViewModel(t); 
    } 
} 
+0

奇怪 - 我可以看到,如果应用才刚刚装(新实例),因为引导程序可能没有踢和注册的所有意见,但话又说回来,这可能发生我不知道RT,所以我不能肯定地告诉你应用恢复时事件的顺序。你有没有尝试把这个引导程序放在'Configure'方法中(在调用base.Configure()之后?) - 我在想,至少这会在应用程序初始化之后进行,所以视图应该准备好去 – Charleh

+0

谢谢,但是如果我尝试在Configure的末尾插入导航到VM代码(甚至在调用base.Configure()之后;这是否需要重写CM中的Configure方法?),我得到的所有内容都是另一个异常告诉我IoC尚未配置。 – Naftis

+0

CM的创建者有一篇有趣的文章[here](http://caliburnmicro.com/announcements/application-state-part-3/)。它提出了一些想法,但没有提供实施。它虽然开了一个讨论。也请看[this](https://github.com/Caliburn-Micro/Caliburn.Micro/issues/95) – Corcus

回答

0

我尝试这样做,似乎工作,但我觉得有点不安全。因为在CM生命周期处理的8.1似乎并没有成为我的应用程序的健壮性明确记录,所以我想从社区获得评论或更正。首先覆盖PrepareViewFirst方法:

protected override void PrepareViewFirst(Frame rootFrame) 
{ 
    _container.RegisterNavigationService(rootFrame); 
} 

然后在OnLaunched覆盖,在那里之前,我刚刚打电话DisplayRootView<MainView>(),我测试的参数传递给检查我们是否从暂停状态恢复,如果是这样我浏览到以前的活动页面;别的我只是去像以前一样:

protected override void OnLaunched(LaunchActivatedEventArgs args) 
{ 
    bool bResumed = false; 
    if (args.PreviousExecutionState == ApplicationExecutionState.Suspended) 
    { 
     AppSimpleState state = LoadState(); 
     string sType = state.Get(APP_CURRENTVM_KEY); 
     if (sType != null) 
     { 
      INavigationService navigation = IoC.Get<INavigationService>(); 
      Type t = Type.GetType(sType); 
      Debug.Assert(t != null); 
      navigation.NavigateToViewModel(t); 
      bResumed = true; 
     } //eif 
    } 

    if (!bResumed) DisplayRootView<MainView>(); 
} 
+0

当我开始写一些RT应用程序时,我会回来告诉你,如果我找到了一个更好的方法来做到这一点 - 我目前正在编写一些机器人的东西,所以没有达到RT部分,如果你找到一个更好的地方来放置它,请做更新。替代方案(以及我经常做的事情)是查看CodePlex上的CM源,并从引导程序开始通过它运行。它写得很好,容易遵循,所以你会学到很多关于事件的顺序。 – Charleh