3

我想知道是否有一种“简单”/好方法来检查属性是否已更改。就像下面的层次结构中 Child.Name 已更改(isDirty)一样,我想知道。

GrantParent
- Parent
-- Child

在我目前的情况下,我需要浏览模型以查看是否有任何变化。

ps:我正在使用IChangeTracking.

一直在考虑缓存序列化对象的哈希。(太慢了?)

或者创建调用的父级的changedevent,直到它到达授权父级。(健谈?)

  public class Parent: BaseEntity
  {
    private Child _child;
    public Child Child
    {
      get { return _child; }
      set { _child = value; OnPropertyChanged("Child"); }
    }
  }

  public class Child : BaseEntity
  {
    private  int _id;
    public int Id {
      get { return _id; }
      set { _id = value; OnPropertyChanged("Id"); }
    }
  }



 [DataContract]
  [Serializable]
  public abstract class BaseEntity : INotifyPropertyChanged
  {
    protected BaseEntity()
    {
      PropertyChanged += PropertyChangedEventHandler;
    }

    private void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e)
    {
      if (e != null && !String.Equals(e.PropertyName, "IsChanged", StringComparison.Ordinal))
      {
        this.IsChanged = true;
      }
    }

    protected void OnPropertyChanged<T>(Expression<Func<T>> property)
    {
      MemberExpression me = property.Body as MemberExpression;
      if (me == null || me.Expression != property.Parameters[0]
            || me.Member.MemberType != MemberTypes.Property)
      {
        throw new InvalidOperationException(
            "Now tell me about the property");
      }
      var handler = PropertyChanged;
      if (handler != null) handler(this,
        new PropertyChangedEventArgs(me.Member.Name));
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool IsChanged
    {
      get
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          return _notifyingObjectIsChanged;
        }
      }

      protected set
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          if (!Boolean.Equals(_notifyingObjectIsChanged, value))
          {
            _notifyingObjectIsChanged = value;

            if (IsDirtyChanged != null)
              IsDirtyChanged();

            this.OnPropertyChanged("IsChanged");
          }
        }
      }
    }

    private bool _notifyingObjectIsChanged;
    private readonly object _notifyingObjectIsChangedSyncRoot = new Object();

    public void AcceptChanges()
    {
      this.IsChanged = false;
    }
  }

最后,我对已经使用的 XML 序列化程序中的 XML 模型进行了比较。我不需要每秒(左右)一次即时更改检测就足够了。现在我用上次保存后的那个来检查 XML 模型。

4

2 回答 2

3

您需要让每个属性自己跟踪它,并存储一些指示哪些属性已更改的信息,或者可能在项目更改时触发事件。

基本上每个属性都会有类似的逻辑:

public class MyClass : INotifyPropertyChanged
{
    private int _value;
    public int Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

这将允许您向 PropertyChanged 事件添加事件处理程序,以便在更改属性时触发代码。

于 2012-10-26T14:23:45.740 回答
2

我最近在一个项目中工作,我们让所有节点/叶子实现一个node.Modified属性并用于INotifyPropertyChanged引发node.Modified. 然后所有的父母都订阅了他们孩子的财产变更,如果node.Modified曾经设置为真,那么他们会将自己的设置node.Modified为真。

就像你说的,它有点啰嗦,但还没有接近成为我们的性能瓶颈,因为我们没有看到每秒成千上万的变化,而且我们的层次结构只有 3 级深。

这是一个快速示例:

class Node : INotifyPropertyChanged
{

    public Node()
    {
        Children = new List<Node>();
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        var temp = PropertyChanged;
        if (temp != null)
            temp(this, new PropertyChangedEventArgs(name));
    }

    public IList<Node> Children { get; private set; }
    public void AddChild(Node node)
    {
        node.PropertyChanged += ChildPropertyChanged;
        Children.Add(node);
    }

    void ChildPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "Modified")
            Modified |= ((Node)sender).Modified;
    }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;
                OnPropertyChanged("Modified");
            }

        } 
    }

编辑:还有另一种使用消息总线的方法。它可能并不完美,但它是解决问题的另一种方法,所以我也会分享。我很快就破解了一个微不足道的消息总线......

static class Bus<T>
{

    public static Dictionary<object, Action<object, T>> Subscriptions = new Dictionary<object, Action<object, T>>();
    public static void Raise(object sender, T message)
    {
        foreach (Action<object, T> action in Subscriptions.Values)
        {
            action(sender, message);
        }
    }

    public static void Subscribe(object subscriber, Action<object, T> action)
    {
        Subscriptions[subscriber] = action;
    }

    public static void Unsubscribe(object subscriber)
    {
        if (Subscriptions.ContainsKey(subscriber))
            Subscriptions.Remove(subscriber);
    }

}

public class WasModified { }

和修改后的节点

class Node
{

    public Node()
    {
        Children = new List<Node>();
    }

    public IList<Node> Children { get; private set; }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;

                if (_modified == true)
                    Bus<WasModified>.Raise(this, new WasModified());
            }

        } 
    }
}

最后,它的用途。

    static void Main(string[] args)
    {

        Node parent = new Node();
        Bus<WasModified>.Subscribe(parent, (s,a)=> parent.Modified = true);
        Node child = new Node();
        Node gchild = new Node();
        parent.Children.Add(child);
        parent.Children.Add(gchild);
        gchild.Modified = true;
        Console.WriteLine(parent.Modified);


        Console.ReadLine();
    }

消息总线不需要冒泡到父对象,并且每次您想查看 Modified 是否已更改时都不需要递归到它们,所以也许这就是您要查找的内容。

于 2012-10-26T14:35:32.177 回答