WPF/Silverlight序列化可能顺序可能丢失PropertyChanged,造成通知失效

来源:互联网 发布:sew变频器调试软件 编辑:程序博客网 时间:2024/06/07 01:22

 PropertyChanged:

public class MetaRecord : DomainObject
        {

            #region **属性成员
            private MetaSample _试样1;
            public MetaSample 试样1 {
                get
                {
                    return _试样1;
                }
                set{
                    _试样1=value;
                    this.RaisePropertyChanged(()=>试样1);
                }
            }

            public MetaSample 试样2 { get; set; }

            public MetaSample 试样3 { get; set; }

            //可溶物含量计算的公式:A=(m2-m3)*100,保留1位小数。
            private double _可溶物含量;
            public double 可溶物含量
            {
                get
                {
                    _可溶物含量 = Math.Round(( 试样1.可溶物含量 + 试样2.可溶物含量 + 试样3.可溶物含量 ) / 3, 1);
                    return _可溶物含量;


                }
                set
                {
                    //_可溶物含量 = value;
                    _可溶物含量 = Math.Round(( 试样1.可溶物含量 + 试样2.可溶物含量 + 试样3.可溶物含量 ) / 3, 1);
                    this.RaisePropertyChanged(() => this.可溶物含量);
                }
            }
            #endregion

            #region **方法成员
            public MetaRecord()
            {
                试样1 = new MetaSample();
                试样2 = new MetaSample();
                试样3 = new MetaSample();

                //捕获内部对象的改变
                试样1.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
                试样2.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
                试样3.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
                               
            }

           
            private void value_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                this.RaisePropertyChanged(() => this.可溶物含量);
            }
            #endregion

        }

        /// <summary>
        /// 试样信息
        /// </summary>
        public class MetaSample : DomainObject
        {
            #region 属性成员

            private double _萃取前重量;
            public double 萃取前重量
            {
                get
                {
                    return _萃取前重量;
                }
                set
                {
                    if ( _萃取后重量 != 0 && value != 0 )
                        if ( _萃取后重量 > value )
                        {
                            throw new Exception("【萃取后重量M3】不能大于【萃取前的重量M2】!");
                        }

                    _萃取前重量 = value;
                    this.RaisePropertyChanged(() => this.可溶物含量);
                    this.RaisePropertyChanged(() => this.萃取前重量);
                    this.RaisePropertyChanged(() => this.萃取后重量);

                }
            }

            private double _萃取后重量;
            public double 萃取后重量
            {
                get
                {
                    return _萃取后重量;
                }

                set
                {
                    if ( value != 0 && _萃取前重量 != 0 )
                        if ( value > _萃取前重量 )
                        {
                            throw new Exception("【萃取后重量M3】不能大于【萃取前的重量M2】!");
                        }

                    _萃取后重量 = value;
                    this.RaisePropertyChanged(() => this.可溶物含量);
                    this.RaisePropertyChanged(() => this.萃取前重量);
                    this.RaisePropertyChanged(() => this.萃取后重量);
                }
            }

            private double _可溶物含量;
            public double 可溶物含量
            {
                get
                {
                    //===============================================================
                    _可溶物含量 = Math.Round(( 萃取前重量 - 萃取后重量 ) * 100, 1);
                    return _可溶物含量;
                }
                set
                {
                    _可溶物含量 = Math.Round(( 萃取前重量 - 萃取后重量 ) * 100, 1);
                    this.RaisePropertyChanged(() => this.可溶物含量);
                }
            }

            #endregion
            //===============
        }

//================

        //[OnDeserialized()]
        //internal void OnDeserializedMethod(StreamingContext context)
        //{
        //    试样1.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(value_PropertyChanged);
        //    试样2.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(value_PropertyChanged);
        //    试样3.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(value_PropertyChanged);
        //}

 ============================================================================

代码分析:

上述代码MetaRecord,通过反序列化,构建MetaSample,,但是反序列化又会重新构建MetaSample.

            试样1.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
                试样2.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
                试样3.PropertyChanged += new PropertyChangedEventHandler(value_PropertyChanged);
这些代码可能失效。

 

结果属性通知失败。

C#的序列化,序列化MetaRecord的成员调用new MetaRecord(),事件PropertyChanged 被挂载,结果读取MetaSample的时候,对原来的PropertyChanged 进行清空,结果序列化就消失了。PropertyChanged =null,序列化失效了。

 

解决办法:

1)现在我自己开发序列化和序列化的工具,更重要的是避免序列化带来的版本异常问题。还有有时需要对只读对象进行强制序列化。

2)分析上述原理,你可以删除MetaSample的构造函数New MetaRecord(),建立一个非空的进行调用,避免反序列化调用此函数。或者将次方法不能做成Public不能外部调用,避免反序列化调用引起的其他属性丢失的问题。

3)试过调用反序列化的事件,反而繁琐了。因为是要处理MetaSample丢失PropertyChanged 的问题。麻烦了。

 

=====网络摘录-================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Xml;

namespace ReadDBLP
{
    class ReadDBLP
    {

        public class MyResolver : XmlUrlResolver
        {
            public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
            {
                if (absoluteUri.AbsoluteUri == "D:/people.dtd")
                {
                    return File.Open("people.dtd", FileMode.Open);
                }

                return base.GetEntity(absoluteUri, role, ofObjectToReturn);
            }

        }

        public void Load(string path)
        {
         
            XmlReaderSettings settings=new XmlReaderSettings();
            settings.ValidationType = ValidationType.DTD;
            settings.ProhibitDtd = false;
            settings.XmlResolver = new MyResolver();
            using (XmlReader reader = XmlReader.Create("D:/people.xml", settings))
            {
                XDocument document = XDocument.Load(reader);
            }

        }
    }