WPF: MVVM中ViewModel数据存储/序列化的尴尬
<div class="postcontent"><div id="cnblogs_post_body">示例程序,当然是用MVVM模式写的,支持ViewModel数据的存储,读取,和清空。用户点击“存储”后,整个ViewModel的数据会被存储到硬盘中,连列表中的选中项目也会被记录。选择“清空”后,整个ViewModel会被清空,那么界面上TextBox值为空,ListBox也不会包含任何数据。最后选择“读取”后,之前存储的数据会立刻被还原。http://images.cnblogs.com/cnblogs_com/mgen/201210/201210030032596433.png
具体怎么做,没有完全用.NET中的传统序列化方式,这也是为什么标题会有尴尬两字,干扰ViewModel直接序列化的因素我看到的有两点:
[*]ViewModel中通常有大量的自动属性,序列化是依靠字段名称的,自动属性由编译器生成名称,因此无法保证序列化数据的通用性。
[*]一些框架的ViewModel基类没有被标记有Serializable特性。比如MVVM Light,参考这个链接。
因此程序在ViewModel中加入了一些数据操作的借口,提供数据的清空,读取和保存操作,数据的操作当然可以有复杂的类型,这里我们以最基础的IDictionary<string, object>做示范。当然这个IDictionary<string, object>最终会以.NET序列化的方式存储到硬盘中,因此这里做的就是把ViewModel中的数据抽象到一个中间存储中,这个中间存储是有利于序列化的,比如IDictionary<string, object>。还有一些需要注意的问题,比如会有许多ViewModel,但是只有一个IDictionary<string, object>。如果只在一个IDictionary<string, object>的根层存储的话,命名会是个问题,因此需要加入一些辅助操作来在一个IDictionary<string, object>定义另一个子IDictionary<string, object>,对应一个ViewModel中的子ViewModel,每一个ViewModel都有自己的存储空间。最后的存储和读取在多个IDictionary<string, object>中跳转。
那么,这样定义我们的ViewModel:
<div class="mgen_code" style="border-top: gray 1px solid; border-right: gray 1px solid; border-bottom: gray 1px solid; padding-bottom: 10px; padding-top: 10px; padding-left: 10px; margin: 12px; border-left: gray 1px solid; padding-right: 10px; background-color: #262626"> using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using GalaSoft.MvvmLight;
namespace mgen_mvvmStorage
{
//继承MVVM Light中的ViewModelBase
class LogicBase : ViewModelBase
{
//清空数据
public virtual void ClearStates()
{ }
//读取数据
public virtual void LoadStates(IDictionary<string, object> states)
{
ClearStates();
}
//保存数据
public virtual void SaveStates(IDictionary<string, object> states)
{ }
//添加数据槽
public IDictionary<string, object> NewSlot(IDictionary<string, object> states, string name)
{
var dic = new Dictionary<string, object>();
states = dic;
return dic;
}
//获取数据槽
public IDictionary<string, object> GetSlot(IDictionary<string, object> states, string name)
{
return (IDictionary<string, object>)states;
}
//利用CallerMemberName进行属性改变通知
protected virtual bool RaisePropertyChangedEx<T>(ref T oldValue, T newValue, bool broadcast, [CallerMemberName] string prop = null)
{
if (!Object.Equals(oldValue, newValue))
{
oldValue = newValue;
RaisePropertyChanged(prop, oldValue, newValue, broadcast);
return true;
}
return false;
}
}
}
页:
[1]