使用序列化检查对象的状态更改?

时间:2010-03-17 22:11:55

标签: c# .net

我有一个绑定到对象的表单,当用户试图离开表单时,我想警告他们表单上是否有任何更改,并提示他们保存。我的问题是,如果没有为绑定对象中的所有类实现IComparar,有没有办法实现这一点?我在想是否有一种方法可以在加载表单时序列化我的对象,并对也被序列化的更改对象进行简单的比较。像字符串比较的东西。

希望有意义,

由于

3 个答案:

答案 0 :(得分:1)

这是asked before,通过序列化比较2个对象树 答案是:它不可靠,有相同对象的反例生成不同的序列化文本/数据。

答案 1 :(得分:1)

如果您遵循人们在实施 INotifyPropertyChanged 时使用的常规模式,那么只需要几行代码来实现IsDirty(或 IsChanged >)数据对象上的标志。

首先,创建一个实现基础的基类,以及一个从中派生的真实数据类:

public class BaseDataObject : INotifyPropertyChanged
{

    public bool IsDirty
    {
        get { return _isDirty; }
        protected set { _isDirty = value; }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        _isDirty = true;

        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    private bool _isDirty;
}


public class MyRealDataObject : BaseDataObject
{
    public int MyIntProperty
    {
        get { return _myIntProperty; }
        set
        {
            bool changed = _myIntProperty != value;
            if (changed)
            {
                _myIntProperty = value;
                OnPropertyChanged("MyIntProperty");
            }
        }
    }

    private int _myIntProperty;
}

现在每当可通知​​的属性发生更改时,数据对象的IsDirty标志将设置为true。要检查更改,您所要做的就是枚举您的对象集合并检查IsDirty标志。如果你聪明,你可以使用LINQ语句:

bool changesMade = MyDataObjectCollection.Any(p => p.IsDirty == true).Count() > 0; 

... or ....

bool changesMade = MyDataObjectCollection.Count(p => p.IsDirty == true) > 0;

如果您的数据对象不在一个好的集合中,您只需手动迭代它们。当然上面的模式可以通过几种不同的方式进行重构(嘿,也许你甚至不使用INotifyPropertyChanged,因为你不是数据绑定到UI元素),但它为你提供了一个很好的开始示例,说明如何实现你想要的。

答案 2 :(得分:0)

要做你想做的事情,可能有一个更简单的方法:使用“修改”的标志或事件。

如果需要,您可以将此级别的用户控件级联起来。只需声明这样的事件:

public class MyControl : Control
{
    public MyControl()
    {
        InitializeComponent();
        textBox1.TextChanged += BubbleModified;
        // etc.
    }

    protected void BubbleModified(object sender, EventArgs e)
    {
        OnModified(e);
    }

    protected void OnModified(EventArgs e)
    {
        var handler = Modified;
        if (handler != null)
            handler(this, e);
    }

    [Category("Behavior")]
    [Description("Occurs when data on the control is modified.")]
    public event EventHandler Modified;
}

然后,无论您需要实际检查修改的任何级别,都要挂钩所有事件。

public class MainForm : Form
{
    private bool isDataModified;

    public MainForm()
    {
        InitializeComponent();

        textBox1.TextChanged += DataModified;
        textBox2.TextChanged += DataModified;
        // etc.
        userControl1.Modified += DataModified;
        userControl2.Modified += DataModified;
        // etc.
    }

    private void DataModified(object sender, EventArgs e)
    {
        isDataModified = true;
    }
}

然后你要做的就是相应地检查(并重置)isDataModified标志。

这确实不是很多工作,当然比确保为图中的每个对象实现INotifyPropertyChanged更容易。请记住,这是一个表单,您并不关心对象是否已更改,您关心用户是否进行了更改,为此,您要实际检查通过控制进行的更改。

是的,它并不完美 - 即使用户更改某些内容然后将其更改回来,您仍会遇到报告数据发生变化的轻微麻烦。但我认为我从未真正听到过这方面的抱怨,并且使用序列化作为比较方法并不可靠。如果要消除冗余保存确认,您真正需要做的是覆盖图中每个对象的Equals方法,并实现实际的值相等操作。或者,如果您不想保留旧图的副本,请使用校验和生成函数(可能发生冲突,但极不可能发生冲突)。

但我会坚持用旗帜。不要试图欺骗你写出平等检查的方法。它实际上与尝试编写自动深度克隆方法相同;你可以尝试,但你提出的任何事情都会被打破有时候