2009-08-21 23 views
15

私はこのデータを含む仮想ツリービューを持っています:ICollectionViewを使用してwpfツリービューの階層をフィルタリングする方法は?

RootNode 
    Leaf 
    vein 
SecondRoot 
    seeds 
    flowers 

特定のテキストを含むノードだけを表示するために、ノードをフィルタリングしようとしています。 "L"を指定すると、ツリーはフィルタリングされ、RootNode-> LeafとSecondRoot-> flowers(両方に文字Lが含まれているため)だけが表示されます。

MV-VMのパターンに続いて、私はこのような基本的なTreeViewViewModelクラスを持っている:

public class ToolboxViewModel 
{ 
    ... 
    readonly ObservableCollection<TreeViewItemViewModel> _treeViewItems = new ObservableCollection<TreeViewItemViewModel>(); 
    public ObservableCollection<TreeViewItemViewModel> Headers 
    { 
     get { return _treeViewItems; } 
    } 

    private string _filterText; 
    public string FilterText 
    { 
     get { return _filterText; } 
     set 
     { 
      if (value == _filterText) 
       return; 

      _filterText = value; 

      ICollectionView view = CollectionViewSource.GetDefaultView(Headers); 
      view.Filter = obj => ((TreeViewItemViewModel)obj).ShowNode(_filterText); 
     } 
    } 
    ... 
} 

そして、基本的なTreeViewItemViewModel:

public class ToolboxItemViewModel 
{ 
    ... 
    public string Name { get; private set; } 
    public ObservableCollection<TreeViewItemViewModel> Children { get; private set; } 
    public bool ShowNode(string filterText) 
    { 
     ... return true if filterText is contained in Name or has children that contain filterText ... 
    } 
    ... 
} 

すべてがXAMLで設定があるので、私は、ツリービューを参照してください検索ボックス。

このコードを実行すると、フィルターはルートノードにのみ不十分です。私の述語がすべてのノードに対して呼び出されるように、ノードの階層内でフィルタを細かくする方法がありますか?言い換えれば、フィルタは全体としてTreeViewに適用できますか?

+2

?あなたが中継することができる、または他の解決方法のパフォーマンス情報? –

答えて

3

残念ながら、同じフィルタをすべてのノードに自動的に適用する方法はありません。 FilterはDependencyObjectではないItemsCollectionのプロパティ(DPではない)であるため、DP Valueの継承は存在しません。

ツリー内の各ノードには独自のフィルタを持つ独自のItemsCollectionがあります。それを有効にする唯一の方法は、すべて同じ代理人を呼び出すように手動で設定することです。

最も簡単な方法は、ToolBoxViewModelでプレディケート<オブジェクト>のフィルタプロパティを公開し、そのセッターでイベントを発生させることです。その後、ToolboxItemViewModelはこのイベントを消費し、そのフィルタを更新します。

かなり良いですが、ツリー内の大量のアイテムのパフォーマンスがどうなるかわかりません。

2

これを行うには(これは少しハックです)わかった唯一の方法は、IListからIEnumerableに変換するValueConverterを作成することです。 ConvertTo()で渡されたIListから新しいCollectionViewSourceを返します。

もっと良い方法があれば、聞いてみたいです。しかし、これはうまくいくようです。

0

あなたはItemContainerGeneratorを使用してツリー内の特定の要素のTreeViewItemを取得し、フィルタを設定することができます。

6

これは私が私のTreeView上の項目をフィルタ処理する方法である:

私はクラスを持っている:

class Node 
{ 
    public string Name { get; set; } 
    public List<Node> Children { get; set; } 

    // this is the magic method! 
    public Node Search(Func<Node, bool> predicate) 
    { 
     // if node is a leaf 
     if(this.Children == null || this.Children.Count == 0) 
     { 
      if (predicate(this)) 
       return this; 
      else 
       return null; 
     } 
     else // Otherwise if node is not a leaf 
     { 
      var results = Children 
           .Select(i => i.Search(predicate)) 
           .Where(i => i != null).ToList(); 

      if (results.Any()){ 
       var result = (Node)MemberwiseClone(); 
       result.Items = results; 
       return result; 
      } 
      return null; 
     }    
    } 
} 

としてその後、私は結果をフィルタリングすることができます:あなたは何をして終わるんでした

// initialize Node root 
// pretend root has some children and those children have more children 
// then filter the results as: 
var newRootNode = root.Search(x=>x.Name == "Foo"); 
関連する問題