0

몇 가지 기본 차트/그래프 기능이있는 사용자 정의 컨트롤을 만드는 중입니다. 본질적으로 컨트롤의 사용자가 바인딩 할 수있는 "Items"종속성 속성을 갖고 싶습니다. 그러면 컨트롤에서 소스에 대한 모든 항목과 업데이트를 표시합니다.사용자 만들기 차트 작성을위한 항목 만들기

내가 지금까지 한 것은 사용자 컨트롤에 코드 "DP"를 만드는 것입니다.

public static readonly DependencyProperty ItemsProperty = 
    DependencyProperty.Register("Items", 
    typeof(ObservableCollection<Polyline>), 
    typeof(RPGraph), 
    new FrameworkPropertyMetadata(
    new ObservableCollection<Polyline>(), 
    new PropertyChangedCallback(OnItemsChanged))); 

public ObservableCollection<Polyline> Items 
{ 
    get { return (ObservableCollection<Polyline>)GetValue(ItemsProperty); } 
    set { SetValue(ItemsProperty, value); } 
} 

public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
} 

내 첫 번째 걸림돌은 컬렉션이 변경되었을 때 "OnItemsChanged"가 호출되지 않는다는 것입니다. 두 시간 후 왜 stackoverflow 게시물 (ObservableCollection dependency property does not update when item in collection is deleted) 설명을 발견했다. 이 조언을 따라하면 내 문제의 한 부분이 해결되었습니다. 이제 ObservableCollection 목록에 새 항목 (폴리 라인)을 추가 할 수있었습니다. 그러나 폴리 라인에 추가 점을 추가하거나 점을 수정하면 어떻게됩니까? 이전 문제에 대한 지식으로 무장 한 Points.Changed 이벤트를 발견했습니다. 그 다음에 구독하고 거기에 업데이트 코드를 넣었습니다.

이 작업은 마침내 가능하지만 더 나은 또는 더 우아한 방법으로이 작업을 수행해야합니다 (상단에 명시된 바와 같이). ObservableCollection을 사용하지 않는 것으로 생각합니다. 어떤 충고? 다음은

이 작업 OnItemChanged 방법 (초안 코드를 변명이다, 난 그냥 :-) 작업을 얻을 싶었 : ObservableCollection이 알리지 않습니다

public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    {  
     var thisControl = d as RPGraph; 

     foreach (Polyline poly in thisControl.Items) 
      thisControl.manager.Items.Add(poly.Points.ToArray()); 

     if (e.OldValue != null) 
     { 
      var coll = (INotifyCollectionChanged)e.OldValue; 

      // Unsubscribe from CollectionChanged on the old collection 
      coll.CollectionChanged -= Items_CollectionChanged; 
     } 

     if (e.NewValue != null) 
     { 
      var coll = (ObservableCollection<Polyline>)e.NewValue; 

      // Subscribe to CollectionChanged on the new collection 
      coll.CollectionChanged += (o, t) => { 
       ObservableCollection<Polyline> items = o as ObservableCollection<Polyline>; 

       thisControl.manager.Items.Add(items[t.NewStartingIndex].Points.ToArray()); 

       foreach (Polyline poly in items) 
       { 
        poly.Points.Changed += (n, m) => { 

         for (int i = 0; i < thisControl.manager.Items.Count; i++) 
          thisControl.manager.Items[i] = thisControl.Items[i].Points.ToArray(); 

         thisControl.manager.DrawGraph(thisControl.graphView); 
        }; 
       } 
       thisControl.manager.DrawGraph(thisControl.graphView); 
      }; 
     } 
     thisControl.manager.DrawGraph(thisControl.graphView); 
    } 
+0

AFAIK이 작업을 수행하는 다른 방법은 없습니다. 모니터하려는 계층 구조의 각 레벨에서 이벤트 핸들러를 사용해야합니다. 예를 들어, 목록을 모니터링하여 삽입 및 삭제를 감지 한 다음 목록의 각 요소를 모니터링하여 속성이 변경된시기 등을 감지합니다.주의했듯이이 코드는 복잡하고 장황한 코드로 이어집니다. –

답변

0

당신은 완전히 잘 때 해당 항목의 변경 사항 속성 값.

ObservableCollection의 기능을 확장하여 이러한 경우에 대한 알림을 추가 할 수 있습니다.

그것은 다음과 같이 보일 수 있습니다 :

public sealed class ObservableNotifiableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged 
{ 
    public event ItemPropertyChangedEventHandler ItemPropertyChanged; 
    public event EventHandler CollectionCleared; 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) 
    { 
     base.OnCollectionChanged(args); 

     if (args.NewItems != null) 
     { 
      foreach (INotifyPropertyChanged item in args.NewItems) 
      { 
       item.PropertyChanged += this.OnItemPropertyChanged; 
      } 
     } 

     if (args.OldItems != null) 
     { 
      foreach (INotifyPropertyChanged item in args.OldItems) 
      { 
       item.PropertyChanged -= this.OnItemPropertyChanged; 
      } 
     } 
    } 

    protected override void ClearItems() 
    { 
     foreach (INotifyPropertyChanged item in this.Items) 
     { 
      item.PropertyChanged -= this.OnItemPropertyChanged; 
     } 

     base.ClearItems(); 
     this.OnCollectionCleared(); 
    } 

    private void OnCollectionCleared() 
    { 
     EventHandler eventHandler = this.CollectionCleared; 
     if (eventHandler != null) 
     { 
      eventHandler(this, EventArgs.Empty); 
     } 
    } 

    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs args) 
    { 
     ItemPropertyChangedEventHandler eventHandler = this.ItemPropertyChanged; 
     if (eventHandler != null) 
     { 
      eventHandler(this, new ItemPropertyChangedEventArgs(sender, args.PropertyName)); 
     } 
    } 
} 

그런 다음 당신이 ItemPropertyChanged 이벤트에 가입하고 물건을 할 수 있습니다.

+0

이것은 훨씬 더 나은 접근 방법으로 보이며 재사용 가능한 솔루션을 제공합니다. 이 솔루션에 맞춰 더 많은 검색을 한 후에 실제로이 질문에 대한 답변이 이미 있음을 알았습니다. http://stackoverflow.com/questions/269073/observablecollection-that-also-monitors-changes-on-the- elements-in-collection은 왜 ClearItems 등을 덮어 쓸 필요가 있는지 설명합니다. 감사합니다. 그것은 새로운 세계를 열었습니다. 위의 코드에 대해서는 INotifyPropertChanged 권한을 구현하는 객체에서만 작동합니다. – Avalan

+1

@Avalan, 맞습니다. 이것이 왜'where T : INotifyPropertyChanged'를 보는 이유입니다. 'PropertyChanged' 이벤트가 필요합니다. 또는이 코드를 업데이트하고 인터페이스를 명시 적으로 요구하는 대신 오리 입력을 사용할 수 있습니다. – dymanoid

+0

니스! 방금 새로운 것을 배웠습니다. "덕 타이핑"(좋은 설명은 여기에 있습니다 : http://ericlippert.com/2014/01/02/what-is-duck-typing) 감사합니다. 깔끔한 코드 조각! – Avalan