首页 > 代码库 > Catel帮助手册-Catel.Core:(4)数据处理

Catel帮助手册-Catel.Core:(4)数据处理

1,概要

 

   文档的这个部分都是关于Catel中数据处理方法的,一些部分是基于CodeProject上的文章的,但这个文档有更多的更新内容。

    一件很重要的事情是许多开发者花费很多时间来处理对象的序列化,序列化是一个专业领域的知识,只有技术比较高深的人员才能很好地掌握对象的序列化处理(要考虑程序集的改变,类的改变(属性的增加和移除),大部分开发者认为序列化只是执行如下的操作代码创建一个BinaryFormattter对象:

var serializer = new BinaryFormatter();var myObject = (MyObject)serializer.Deserialize(stream);

大部分的开发者并不知道在如下情况下,序列化会出现问题

1,你更改了你的程序集版本

2,你增加或减少了一个属性字段

3,你增加或减少了一个事件

  甚至如果你知道,它也需要很多的知识点来解决这个问题,我也是在我足够能够把握这个知识点后才来编写序列化的方法,这个方法是ModelBase类,这个能作为数据对象的基类使用,可以存储到内存也可以序列化到磁盘(或者stream,或者XML,等等…)

2,ObservableObject对象

ObservableObject对象是一个非常轻量级的类仅仅实现了INotifyPropertyChanging和INotifyPropertyChanged接口,这个类是简单对象,仅仅需要属性通知,下面是一个例子:

 

 

public class Person : ObservableObject{    private string _firstName;    private string _middleName;    private string _lastName;     public Person(string firstName, string middleName, string lastName)    {        FirstName = firstName;        MiddleName = middleName;        LastName = lastName;    }     public string FirstName    {        get { return _firstName; }        set        {            RaisePropertyChanging(() => FirstName);                        var oldValue =http://www.mamicode.com/ _firstName;            _firstName = value;            RaisePropertyChanged(() => FirstName, oldValue, value);        }    }     public string MiddleName    {        get { return _middleName; }        set        {            RaisePropertyChanging(() => MiddleName);            var oldValue =http://www.mamicode.com/ _middleName;            _middleName = value;            RaisePropertyChanged(() => MiddleName, oldValue, value);        }    }     public string LastName    {        get { return _lastName; }        set        {            RaisePropertyChanging(() => LastName);            var oldValue =http://www.mamicode.com/ _lastName;            _lastName = value;            RaisePropertyChanged(() => LastName, oldValue, value);        }    }}

3,DispacherObservableObject

DispatchObservableObject是一个类,继承于ObjservableObject类,这个类的唯一不同是,这个对象会将所有的属性更改反应到UI线程上,下面是一个使用DispatcherObservableObject对象的方法,这是一个线程安全的更改观察.

public class Person : DispatcherObservableObject{    private string _firstName;    private string _middleName;    private string _lastName;     public Person(string firstName, string middleName, string lastName)    {        FirstName = firstName;        MiddleName = middleName;        LastName = lastName;    }     public string FirstName    {        get { return _firstName; }        set        {            RaisePropertyChanging(() => FirstName);                        var oldValue =http://www.mamicode.com/ _firstName;            _firstName = value;            RaisePropertyChanged(() => FirstName, oldValue, value);        }    }     public string MiddleName    {        get { return _middleName; }        set        {            RaisePropertyChanging(() => MiddleName);            var oldValue =http://www.mamicode.com/ _middleName;            _middleName = value;            RaisePropertyChanged(() => MiddleName, oldValue, value);        }    }     public string LastName    {        get { return _lastName; }        set        {            RaisePropertyChanging(() => LastName);            var oldValue =http://www.mamicode.com/ _lastName;            _lastName = value;            RaisePropertyChanged(() => LastName, oldValue, value);        }    }}

 

4,ModelBase

ModelBase(以前是DataObjectBase)类,是一个泛型基类,能够被使用到你所有的数据类上.

序列化

可以将对象存储到硬盘或者序列化到内存,或者二进制文件或者XML,数据对象,数据对象支持立即可用,以及动态处理序列化和反序列化。

支持属性变化观察

这个类支持INotifyPropertyChanging和INotifyChanged接口,类能很容易在WPF,Sliverlight和应用程序来给用户反映改变。

  • 向后兼容性
  •  当序列化你的对象到二进制中,很难去维护正确的版本,当你增加了一个新的属性给二进制类,或者更改了命名空间,对象将不能被再载入,data object 对象注意到这个问题,支持向后兼容性。
  • 验证
    这个类实现了IDataErrorInfo接口,,因此他可以验证数据对象检查错误,这样,不需要在类外面写验证代码。
  • 备份和恢复
    这个类实现了IEdiableObject对象接口,这样可以为对象创造一个状态,所有的属性能够被编辑,最终改变可以被提及或者回滚。
  • 4.1 使用类

这个类的使用非常简单,只需要创建一个类继承于ModelBase,如下

/// <summary>/// MyObject class which fully supports serialization,/// property changed notifications, backwards compatibility and error checking./// </summary>#if !SILVERLIGHT[Serializable]#endifpublic class MyObject : ModelBase<MyObject>{    /// <summary>    /// Initializes a new object from scratch.    /// </summary>    public MyObject() { } #if !SILVERLIGHT/// <summary>/// Initializes a new object based on <see cref="SerializationInfo"/>./// </summary>/// <param name="info"><see cref="SerializationInfo"/>//     that contains the information.</param>/// <param name="context"><see cref="StreamingContext"/>.</param>protected MyObject(SerializationInfo info, StreamingContext context)    : base(info, context) { }#endif}

正如你在上面代码中所看到的,MyObject对象继承与ModelBase,并且提供了一个空的构造函数,但是也有一个构造函数用于二进制反序列化,上面的代码看起来复杂,但是这个事事用CodeSnppet来创建的,你只需要填写类的名称即可。

4.1.1 定义属性

为类定义属性也是非常简单,这个与依赖项属性类似,这样定义属性的优点是:

1,属性定义自定包括在序列化中,不需要制定复杂数据接口。

2,你能够为属性指定默认值,当类被构造或者没有在反序列化中发现(在属性被加入到一个存在类的情况)

3,ProperyData对象能够用于返回属性值,编译器可以检查错误,

4,你能够直接订阅改变观察,所有的属性自动支持INotifyPropertyChanged.

下面是字符串代码:

/// <summary>/// Gets or sets the name./// </summary>public string Name{    get { return GetValue<string>(NameProperty); }    set { SetValue(NameProperty, value); }} /// <summary>/// Register the Name property so it is known in the class./// </summary>public static readonly PropertyData NameProperty = RegisterProperty("Name", typeof(string), string.Empty);

一个注册的属性如果需要可以被序列化排除,当对象反序列化时,默认值可以在这种情况下使用。

4.1.2 引用类型的默认值

在许多情况下,引用类型的默认值在定义时是需要的,然而,你可能在依赖属性的理智中注意到这个行为,使用默认值的实例会导致异常行为。

下面是一个“常规”属性,用于定义属性集合

Default values for reference types

 

public static readonly PropertyData NameProperty = RegisterProperty("PersonCollection", typeof(Collection<Person>), new Collection<Person>());

然而,替代创建一个新的集合对象,仅仅一个集合会被创建在使用这个类,一个方案是将null作为默认值,创建这个集合的构造函数,一个更好的解决方案是重写RegisterProperty的回调参数。

 

public static readonly PropertyData NameProperty = RegisterProperty("PersonCollection", typeof(Collection<Person>), new Collection<Person>());

这样,每次新的值需要的时候,回调函数都会创建默认值,你将有对所有引用类型都用默认值。

4.2 提供的功能

ModelBase提供许多立即可用的功能,

INotifyPropertyChanged

所用使用RegisterProperty方法注册的属性自动的关注属性更改。

IDataErrorInfo

很容易使用SetFieldError和SetBussinessError方法设置字段和业务错误,也可以重写ValidateFields和ValidateBusinessRules方法。

IEditableObject

数据对象能够创建一个内部的备份和存储,使用IEditableObject接口

.

Serialization

如前面提到的很多次的,使用SavableModelBase,你能够简单的保存你的对象到stream(文件或者是steam)

记住这个类是不适合数据库传输的,有更好的办法去处理它(通过Entity Framework以及NHibernate,LLBLGenPro提供的ORM匹配)

Catel帮助手册-Catel.Core:(4)数据处理