windows phone mvvm 墓碑化处理.

来源:互联网 发布:织梦dedecms视频教程 编辑:程序博客网 时间:2024/05/09 15:50
我觉的处理墓碑化是一个非常棘手的问题.一旦程序从墓碑化返回当前页面,当前页面的所有数据都为空,会重新调用该页面的构造函数,创建一个新的页面,如果这个页面上没有使用后台代码创建的UI的话,还容易一点,如果有使用后台代码创建的UI,还要需要重新添加UI,然后恢这些UI的状态.我觉得这个过程处理起来会很痛苦,我的想法是把需要动态创建UI的部分做成一个UserControl,在UserControl里面处理创建UI的逻辑.首先在UserControl里面定义依赖属性,然后使用数据绑定技术绑定依赖属性,在ViewModel里面能过参数设置来控件UserControl来动态生成UI.如果顺利的话就可以使用下面这个库来处理墓碑化,另外我觉得顺利处理墓碑化的前提是程序良好的使用了MVVM模式.

下面我来介绍一下MVVM模式的墓碑化处理方式

首先介绍一个库在codeplex上面 叫做 MVVM Tombstone for Windows Phone

http://mvvmtombstone.codeplex.com/SourceControl/latest#WindowsPhone.MVVM.Tombstone/WindowsPhone.MVVM.Tombstone/TombstoneAttribute.cs

1 首先使用NuGet来安装 MVVM Tombstone for windows Phone

2 分别在OnNavigatedFrom和OnNavigatedTo里面添加如下代码

protected override void OnNavigatedTo(NavigationEventArgs e){    base.OnNavigatedTo(e);    TombstoneHelper.page_OnNavigatedTo(this, e);} protected override void OnNavigatedFrom(NavigationEventArgs e){    base.OnNavigatedFrom(e);    TombstoneHelper.page_OnNavigatedFrom(this, e);}

3.在App.cs的Application_Activated 方法中添加如下代码

1
TombstoneHelper.Application_Activated(sender, e);

4.在你需要保存的属性上面加上[Tombstone()]

[Tombstone()]public SomeClass MyObject {   get { return _myobject; }    set {      _myobject = value;      RaisePropertyChanged("MyObject");   }}

OK.啦就是这么简单.想知道是怎么实现了,代码在CodePlex上面.我来介绍一下.代码主要是利用反射,在程序切到后台时,遍历当前ViewModel的带有[Tombstone()]标签的属性,将这些属性的值使用Json.Net进行序列化,然后把序列化的结果保存到PhoneApplicationPage.State字典中,当程序从后台返回到前台时,遍历当前ViewModel的带有[Tombstone()]标签的属性,如果这个属性的值为空,将保存在State字典的值读出来,赋给ViewModel对应的属性.

下面介绍一下源代码

1下面这个类就定义了一个属性标签,标签类似于我们使用的注释,只不过这种标签是给编译器看的,在对ViewModel里面的属性进行保存的时候,就是通过判断对带有这种标签的属性进行保存.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]    public class TombstoneAttribute : Attribute    {    }
 

2.下面这个类就是核心类啦.

 internal class ApplicationState    {        static JsonSerializerSettings settings = new JsonSerializerSettings        {            PreserveReferencesHandling = PreserveReferencesHandling.Objects        };                /// <summary>        /// Runs over all the properties in the page's viewmodel and saves the state of those that have the tombstone attribute applied        /// </summary>        static internal void Save(PhoneApplicationPage page)        {            foreach (PropertyInfo tombstoneProperty in GetTombstoneProperties(page.DataContext))            {                string key = GetKey(tombstoneProperty);                                object value = tombstoneProperty.GetValue(page.DataContext, null);                page.State[key] = JsonConvert.SerializeObject(value, Formatting.None, settings);            }        }        /// <summary>        /// Runs over all the properties in the page's viewmodel and restores the state of those that have the tombstone attribute applied and have no value        /// </summary>        static internal void Restore(PhoneApplicationPage page)        {            foreach (PropertyInfo tombstoneProperty in GetTombstoneProperties(page.DataContext))            {                if (tombstoneProperty.GetValue(page.DataContext, null) == null)                {                    string key = GetKey(tombstoneProperty);                    if (page.State.ContainsKey(key))                    {                        tombstoneProperty.SetValue(page.DataContext, JsonConvert.DeserializeObject((string)page.State[key], tombstoneProperty.PropertyType, settings), null);                    }                }            }        }        /// <summary>        /// Defines the key we are saving in the page's state bag        /// </summary>        private static string GetKey(PropertyInfo Prop)        {            return "tshelper.viewmodel." + Prop.Name;        }        /// <summary>        /// Obtains all the propertyinfos that have the TombstoneAttribute applied       /// <param name="ViewModel">The viewmodel to check. This is set to the page's DataContext</param>            private static IEnumerable<PropertyInfo> GetTombstoneProperties(object ViewModel)    {    if (ViewModel != null) {    IEnumerable<PropertyInfo> tsProps = from p in ViewModel.GetType().GetProperties()                                                 where p.GetCustomAttributes(typeof(TombstoneAttribute), false).Length > 0                                                select p;    foreach (PropertyInfo tsProp in tsProps) {    if (!tsProp.CanRead || !tsProp.CanWrite) {    throw new TombstoneException(string.Format("Cannot restore value of property {0}. Make sure the getter and setter are public", tsProp.Name));    }    }    return tsProps;    } else {    return new List<PropertyInfo>();    }    }    }


GetTombstoneProperties返回带有[Tombstone()]标签的属性的集合.

Restore方法用来在墓碑时恢复数据,遍历带有Tombstone()标签的属性,使用反射从当前的ViewModel中取出属性的值,如果值为空,就从State字典中读出属性的值,反序列化后

把值设置到属性上.

Save方法用来保存数据,遍历带有Tombstone标签的属性,将属性的值序列化后,保存到State字典中.

3.下面这个类是就是我们所使用的接口

 public sealed class TombstoneHelper    {         private static bool _hasbeentombstoned = false;               public static void Application_Activated(object sender, ActivatedEventArgs e)        {            if (!e.IsApplicationInstancePreserved)            {                _hasbeentombstoned = true;            }        }        private static List<PhoneApplicationPage> restoredpages = new List<PhoneApplicationPage>();        public static void page_OnNavigatedTo(PhoneApplicationPage sender, NavigationEventArgs e)        {            if (sender != null && _hasbeentombstoned && !restoredpages.Contains(sender))            {                restoredpages.Add(sender);                ApplicationState.Restore(sender);            }                              }        public static void page_OnNavigatedFrom(PhoneApplicationPage sender, NavigationEventArgs e)        {            if (!(e.NavigationMode == NavigationMode.Back))            {                if (sender != null)                {                    ApplicationState.Save(sender);                }            }        }    }

当离开当前页面时框架会调用OnNavigateedFrom方面,在离开当前页面时分为两种方式,一种方式是用户按下Back键,这时NavigationMode的值为Back.别一种方式是用户按下Start键,程序进入到后来.当程序切到后台进,是否进入墓碑化是不确定的,所以只要程序一进行到后就对数据进行保存.

if (!(e.NavigationMode == NavigationMode.Back))      {}


使用这个判断来排除掉,用户按下Back键的情况.剩下一种当然就是程序切换到后台了.

在page_OnNavigatedTo方法,判断_hasbeentombstoned是否为true,如果为true,并且已经恢复过的页面中不包含当前页面时,恢复数据.(总觉得他设置restoredpages这个List有点多余,干啥还要保存恢复过数据的页面呢)
Application_Activated这个方法就是设置墓碑化标记.

不知道现在还有没有处理墓碑化更好的方法呢?

如果程序不对墓碑进行处理的话,我觉得总是不完美,如果哪位朋友有处理墓碑化更好的方式,请您 一定指教.期待您的回复. 

原创粉丝点击