2012-10-26 6 views
3

속성이 변경되었는지 쉽게 확인할 수있는 좋은 방법이 있는지 궁금합니다. Child.Name이 변경되었을 때 아래의 계층 구조 (isDirty)와 마찬가지로 알고 싶습니다.(있는 경우) (복잡한) pocomodel의 속성이 변경되었는지 확인하는 쉬운 방법은 무엇입니까?

GrantParent 
- Parent 
-- Child 

제 경우에는 모델을 탐색하여 변경된 사항이 있는지 확인해야합니다.

ps : IChangeTracking을 사용하고 있습니다.

직렬화 된 객체의 해시를 캐싱하려고 생각했습니다. (너무 느린가?)

변경된 내용을 생성하는 것은 또는 해당 부모가 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로 설정했습니다.

우리가 1 초마다 수천 건의 변경 사항을 보지 못하고 계층 구조가 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"); 
      } 

     } 
    } 

편집 : 메시지 버스의 종류를 사용하는 또 다른 방법이있다

여기에 빠른 샘플입니다. 그것은 완벽하지 않을 수도 있지만 문제에 대한 또 다른 접근 방법이므로 공유 할 것입니다. 나는 빨리 그것이 소용,

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 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 { } 

그리고 수정 된 노드를 해킹.

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)'변수의 – deepee1

+0

입니다. 비록 내가 컨텍스트를 어떻게 든 감지 할 수 없다면 나는 생각하기에는 프로젝트에 적합하지 않다고 생각한다. 나는 비주얼 스튜디오 디자이너 (Visual Studio Designer)에서 일하고 있는데,이 디자이너는 여러 디자이너가 각각의 작업을 열 수있는 '부모'를 소유하고 있습니다. 그래서 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

관련 문제