2016-09-30 2 views
2

네이티브 WPF 트리 뷰에 다중 선택 지원을 추가하려면 다중 선택된 항목을 저장하는 사용자 지정 종속성 속성을 추가해야했습니다. 이것은 트리의 아이템이 변경되기 전까지 훌륭하게 작동합니다.TreeView Items changed 이벤트

예를 들어 초기 트리에는 하나의 항목 A가 있습니다.이 항목을 선택하면 MultiSelectedItems 목록에 저장됩니다. 그런 다음 아이템 A를 제거하고 아이템 B를 추가했습니다. (ViewModel ObservableCollection 바인딩을 통해)

이런 일이 발생하면 MultiSelectedItems리스트에서 아이템 A를 제거하는 방법을 찾아야합니다.

이벤트를 찾을 수 없습니다. 가장 가까운 것은 ItemContainerGenerator.ItemsChanged 이벤트이지만,이 이벤트는 루트 레벨 노드에서만 시작됩니다 (계층 자식에 대해 실행되지 않음).

답변

0

이 문제를 해결하기위한 핵심 아이디어는 트리 수준이 아닌 각 노드 내에서 변경된 이벤트를 검색하는 것입니다. 노드가, 헤더가 DisconnectedItem라는 감시 객체로 설정됩니다 제거되고 항목 변경 이벤트를 받았을 때

나는 상속 트 리뷰

protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new MultiSelectTreeViewItem(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return item is MultiSelectTreeViewItem; 
    } 

에서 TreeViewItem 클래스

public class MultiSelectTreeViewItem : TreeViewItem 
{ 
    object _originalHeader; 
    protected override void OnHeaderChanged(object oldHeader, object newHeader) 
    { 
     base.OnHeaderChanged(oldHeader, newHeader); 
     //.NET 4.5 use BindingOperations.DisconnectedSource 
     if (newHeader.ToString() != "{DisconnectedItem}") 
      _originalHeader = newHeader; 
    } 

    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) 
    { 
     base.OnItemsChanged(e); 

     if (Header.ToString() == "{DisconnectedItem}" && _originalHeader != null && e.Action == NotifyCollectionChangedAction.Reset) 
     { 
      //Find the parent Tree View and remove this from MultiSelectedList 
     } 
    } 


    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new MultiSelectTreeViewItem(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return item is MultiSelectTreeViewItem; 
    } 
} 

을 상속 NotifyCollectionChangedAction.Reset이됩니다.

List.Clear()을 입력 한 경우 NotifyCollectionChangedAction.Remove 이벤트는 실행되지 않으며, 단지 NotifyCollectionChangedAction.Reset이됩니다. 그래서 나는 그것이 노드 제거를 감지하는 가장 신뢰할 수있는 방법이라고 생각합니다.

노드 하나가 렌더링되지 않은 경우 (부모가 확장되지 않은 경우)이 이벤트는 실행되지 않습니다.

+0

언급 한대로이 방법은 일반적인 의미의 솔루션이 아니며 많은 중요한 오류의 경우가 많습니다. 나는 이전의 대답을 따르는 것이 좋습니다. –

+0

@AndrewHanlon 내가 더 잘 이해할 수 있도록 예제를 사용 하시겠습니까? – Steve

1

불행히도 이것은 복잡한 문제이며 WPF에서 TreeView를 구현하는 몇 가지 방법이 있다는 사실만으로 더욱 복잡해졌습니다. MVVM, 가상화 및 HierarchicalDataTemplates을 사용하는 경우 선택한 항목은 특정 시점에서 시각적 또는 논리적 트리의 일부가 아닐 수도 있습니다. 개별 항목의 제거를 보려는 경우조차도 충분하지 않습니다. 조상은 대신 제거 될 수 있습니다.

는 '부모'와 '루트'노드를 모두 허용 당신의 ViewModel 계층 구조를 통해 액세스 할 수 있도록하고, 항목 수 :

나의 제안은 제어 수준에서 순진한 다중 선택을 구현하고 지능적인 뷰 모델의 계층 구조를 구현하는 것입니다 하위 컬렉션이 변경되면 Root.SelecteItems 컬렉션에서 자손을 제거 할 수 있습니다.

내 MVVM 프레임 워크에서 모든 계층 VM에 사용하는 HierarchicalRootViewModelBaseHierarchicalViewModelBase이 있습니다. 이 방법으로 모든 트리 기능 (예 : 선택 및 수집 변경 이벤트)은 한 번 구현되고 자동으로 처리됩니다. 각 기본 클래스는 부모 노드와 루트 노드에 대한 참조로 구성됩니다 (또는 루트를 찾기 위해 재귀를 사용함).

이렇게하면 계층 구조 깊이에서 항목을 제거하면 SelectedItems 컬렉션을 확인/업데이트하는 것과 같은 루트 수준 작업을 쉽게 트리거 할 수 있습니다.