2012-10-26 28 views
3

我想知道是否有'简单'/好方法来检查一个属性是否已经改变。就像在下面的层次结构中,当Child.Name发生变化时(isDirty),我想知道。(有没有)简单的方法来检查(复杂)pocomodel中的属性是否发生了变化?

GrantParent 
- Parent 
-- Child 

在我目前的情况下,我需要浏览模型,看看是否有任何改变。我正在使用IChangeTracking

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

或者创建changedevent哪个调用是父级,直到它到达grantparent。 (健谈?)

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模型。

+0

透明代理。 – jgauffin

+0

能否详细说明一下?我不熟悉透明代理。 (将查找虽然) –

+0

看看这里:http://stackoverflow.com/questions/8580307/handling-propertychanging-propertychanged-via-castles-dynamicproxy – jgauffin

回答

1

我最近在一个项目中,我们让所有的节点/叶子实现了node.Modified属性,并使用INotifyPropertyChanged来提升node.Modified的状态更改。然后所有的父母都订阅了他们孩子的财产变更,如果node.Modified被设定为真,那么他们将自己的node.Modified设置为true。

就像你说的那样,它有点琐碎,但还没有接近成为我们的性能瓶颈,因为我们没有看到每秒数千次的变化,而且我们的层次结构只有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(); 
    } 

消息总线不需要冒泡到父对象,你不需要你想看看修改改为每次递归到他们,所以也许这是你在找什么。

+0

提高事件是一个显而易见的选择,它将起作用(尽管有点健谈)。消息总线没有引用根节点(除非递归添加这些)。所以我可以检测到一个变化,但不能检测到哪个根节点。 –

+0

@rdkleine当然可以。这是发件人。在Main函数中的上面的例子中,它是'Bus .Subscribe(parent,(s,a)=> parent.Modified = true)的s变量;' – deepee1

+0

好吧,更确切地说,它是任何用户。虽然我喜欢这个想法,但我认为它不适合我的项目,除非我能够以某种方式检测上下文。我正在开发一个Visual Studio Designer,它可以让多个设计人员打开他们自己的'Parent'上的每个工作。所以我必须找出一种方法来知道哪个子节点属于Raise方法中的哪一个父节点。 –

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事件,所以当一个属性更改的代码将被解雇。

+0

我使用IChackTracking为我做这个。我可以打电话给每个对象,询问它是否已经改变,只是我不想问,但以某种方式通知。 –

+0

@rdkleine你可以使用这个事件;请参阅编辑。 – Servy

+0

我同意。作为一个更简单的路线,你可以添加'isChanged'作为对象的属性,但是你必须每次出去检查一次。 – aserwin

相关问题