2012-10-26 55 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

相關問題