2012-12-18 3 views
1

DockPanel에 중첩 된 DataGrid가 있습니다. DockPanel은 데이터 컨텍스트 역할 :ObservableCollection이 수정되었는지 감지합니다.

DockPanel1.DataContext = GetData(); 

GetData의() 메소드는 ObservableCollection에를 반환한다.

ObservableCollection은 DataGrid뿐 아니라 DockPanel에 중첩 된 일부 텍스트 상자에서 수정할 수 있습니다. 또한 DataView를 사용하여 컬렉션을 탐색합니다.

컬렉션이 수정되었는지 감지하고 사용자가 데이터를 저장하지 않고 응용 프로그램을 닫으려고 할 때 경고하고 싶습니다.

사용할 수있는 기본 제공 메커니즘 (컬렉션 또는 뷰에서 일종의 "IsDirty"플래그)이 있습니까? 그렇지 않으면 모든 컨트롤을 모니터링하고 수동으로 변경 사항을 감지해야합니다.

감사 콜렉션 자체의 변화를 감지하기 위해 Leszek이

답변

3

, 당신은 CollectionChanged 핸들러를 첨부해야합니다. 컬렉션에 포함 된 개체의 변경 내용을 검색해야하는 경우 개체가 INotifyPropertyChanged를 구현하는 경우 모든 개체에 PropertyChanged 처리기를 연결해야합니다.

구현은 기본적으로 다음과 같이 보일 것이다 :

var collection = GetData(); 
collection.CollectionChanged += OnCollectionChanged; 

... 

private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    switch (e.Action) 
    { 
     case NotifyCollectionChangedAction.Add: 
      AddPropertyChanged(e.NewItems); 
      break; 
     case NotifyCollectionChangedAction.Remove: 
      RemovePropertyChanged(e.OldItems); 
      break; 
     case NotifyCollectionChangedAction.Replace: 
     case NotifyCollectionChangedAction.Reset: 
      RemovePropertyChanged(e.OldItems); 
      AddPropertyChanged(e.NewItems); 
      break; 
    } 

    ... 
} 

private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    ... 
} 

private void AddPropertyChanged(IEnumerable items) 
{ 
    if (items != null) 
    { 
     foreach (var obj in items.OfType<INotifyPropertyChanged>()) 
     { 
      obj.PropertyChanged += OnPropertyChanged; 
     } 
    } 
} 

private void RemovePropertyChanged(IEnumerable items) 
{ 
    if (items != null) 
    { 
     foreach (var obj in items.OfType<INotifyPropertyChanged>()) 
     { 
      obj.PropertyChanged -= OnPropertyChanged; 
     } 
    } 
} 
1

위 클레멘스 '대답에 조금 정교하게하기 위해, 여기에 구현하기 위해 이러한 이벤트를 사용할 수있는 간단한 방법 (컬렉션에, 그리고 포함 된 항목에 대한) 귀하가 설명한 IsDirty 플래그 :

public class DirtyCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged 
{ 
    private bool isDirty = false; 

    public bool IsDirty 
    { 
     get { return this.isDirty; } 
    } 

    public void Clean() 
    { 
     this.isDirty = false; 
    } 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     // We aren't concerned with how the collection changed, just that it did. 
     this.isDirty = true; 

     // But we do need to add the handlers to detect property changes on each item. 
     switch (e.Action) 
     { 
      case NotifyCollectionChangedAction.Add: 
       this.AddPropertyChanged(e.NewItems); 
       break; 

      case NotifyCollectionChangedAction.Remove: 
       this.RemovePropertyChanged(e.OldItems); 
       break; 

      case NotifyCollectionChangedAction.Replace: 
      case NotifyCollectionChangedAction.Reset: 
       this.RemovePropertyChanged(e.OldItems); 
       this.AddPropertyChanged(e.NewItems); 
       break; 
     } 

     base.OnCollectionChanged(e); 
    } 

    private void AddPropertyChanged(IEnumerable items) 
    { 
     if (items != null) 
     { 
      foreach (var obj in items.OfType<INotifyPropertyChanged>()) 
      { 
       obj.PropertyChanged += OnItemPropertyChanged; 
      } 
     } 
    } 

    private void RemovePropertyChanged(IEnumerable items) 
    { 
     if (items != null) 
     { 
      foreach (var obj in items.OfType<INotifyPropertyChanged>()) 
      { 
       obj.PropertyChanged -= OnItemPropertyChanged; 
      } 
     } 
    } 

    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     // A property of a contained item has changed. 
     this.isDirty = true; 
    } 
} 

코드는 매우 자명합니다.

"T : INotifyPropertyChanged"를 제거하면 해당 인터페이스를 구현하지 않는 개체가 컬렉션에 저장 될 수 있지만 해당 개체에 대한 속성 변경은 통보되지 않습니다. 인터페이스가 없으면 사용자에게 알릴 수 없습니다.

그리고 컬렉션이 더럽지 만, 이벤트 인수에 전달 된 정보를 기록하기 위해 OnCollectionChanged 및 OnItemPropertyChanged의 일부 추가 사항도 잘 기록하고 싶습니다.

+0

감사합니다. Clemens and Cerebrate. 이것은 새로운 프로젝트에서 사용할 아주 좋은 솔루션입니다. 현재 프로젝트에 대해서는 재 작업없이 사용할 수있는 것 같지 않습니다. 우선, 나는 이미 ObservableCollections를 디스크에 일련 화했다. 내가 그들을 deserlize하고 DirtyCollection으로 캐스팅하려고 할 때 예외가 발생합니다. "잘못된 캐스트". 둘째, 내 DirtyCollection에는 DirtyCollection이어야하는 ObservableCollection이라는 멤버가 있습니다. 다시 말해 컬렉션 컬렉션이 있습니다. 방금 ​​간단한 방법으로 작업을 수행하기를 바랐습니다. – Leszek

관련 문제