简体   繁体   English

如何使用 ObservableCollection 数据过滤 treeview

[英]How to filter treeview with ObservableCollection data

I have done a treeview sample and would like to get the result that was shown at below:我做了一个 treeview 示例,并希望获得如下所示的结果:

There have a group of checkboxs (Green, Yellow & Red) and being checked.有一组复选框(绿色、黄色和红色)正在被选中。 Then, have a treeview. As you can see, if one of it's child contains red / yellow color, their parent turn to same color node also.然后,有一个 treeview。如您所见,如果其中一个子节点包含红色/黄色,则它们的父节点也转向相同的颜色节点。 For example, Class A with red node, because Student 3 it's node was red color.例如,Class A 节点是红色的,因为 Student 3 它的节点是红色的。

在此处输入图像描述

How to implement filter tree view function in WPF c#?如何在WPF c#中实现过滤树视图function?

example result,示例结果,

If I unchecked Green checkbox, the result will be:如果我取消选中绿色复选框,结果将是:

在此处输入图像描述

If I unchecked green and yellow, the result will be:如果我取消选中绿色和黄色,结果将是:

在此处输入图像描述

Can get the treeview sample, at here可以在这里获取 treeview 样本

TreeView Sample TreeView样品

Main Window XAML主 Window XAML

<StackPanel Orientation="Vertical">
    <StackPanel Orientation="Vertical">
        <CheckBox Content="Green" Margin="2" />
        <CheckBox Content="Yellow" Margin="2" />
        <CheckBox Content="Red" Margin="2" IsChecked="True" />
    </StackPanel>
    <TreeView ItemsSource="{Binding ClassList}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type loc:Class}" ItemsSource="{Binding Students}">
                <Border Width="150" BorderThickness="1" CornerRadius="2" Margin="2" Padding="2" >
                    <StackPanel Orientation="Horizontal" >
                        <TextBlock  Text="{Binding Name}" FontWeight="Bold"></TextBlock>
                        <Image Margin="2" Source="{Binding ImagePath}"></Image>
                    </StackPanel>
                </Border>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate DataType="{x:Type loc:Student}">
                <Border Width="132" CornerRadius="2" Margin="1" >
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"></ColumnDefinition>
                            <ColumnDefinition Width="26"></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <TextBlock Margin="2"  Text="{Binding Name}" ToolTip="{Binding ToolTip}"></TextBlock>

                        <Image Grid.Column="1" Margin="2" Source="{Binding ImagePath}"></Image>
                    </Grid>
                </Border>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
</StackPanel>

So, you'd need to keep track of TWO collections -- one being the "Filtered" ObservableCollcetion, and the other being the "Master" ObservableCollection (which has the COMPLETE tree). 因此,您需要跟踪两个集合-一个是“过滤的” ObservableCollcetion,另一个是“主”的ObservableCollection(具有COMPLETE树)。

So, whenever you're binding to an ItemsSource for the TreeView, you'll need to be binding to the FilteredObservableCollection. 因此,无论何时绑定到TreeView的ItemsSource,都需要绑定到FilteredObservableCollection。 By default, this collection will be initialized with ALL of the items in the MasterObservableCollection. 默认情况下,将使用MasterObservableCollection中的所有项目初始化此集合。

When someone changes a Checkbox (and its binding is reflected in your ViewModel, ie IsRed = false), you'd have something on your ViewModel update the FilteredObservableCollection. 当某人更改Checkbox(并且其绑定反映在您的ViewModel中,即IsRed = false)时,您会在ViewModel上进行一些操作来更新FilteredObservableCollection。 You would clear ALL items from the FilteredObservableCollection and then loop through the MasterObservableCollection, adding the items that match the criteria into it. 您将清除FilteredObservableCollection中的所有项目,然后遍历MasterObservableCollection,将符合条件的项目添加到其中。

So, some brief pseudo-code from your ViewModel... 因此,您的ViewModel提供了一些简短的伪代码...

ObservableCollection<MyItem> MasterCollection;
ObservableCollection<MyItem> FilteredCollection;
bool IsRed, IsYellow, IsGreen; 

UpdateFilteredCollection()
{
    FilteredCollection.Clear();

    foreach( MyItem item in MasterCollection )
    {
        if( ( item.Color == Green && IsGreen ) || ( item.Color == Yellow && IsYellow ) || ( item.Color == Red && IsRed ) )
        {
            FilteredCollection.Add( item );
            /*
               And do this for child items, etc -- you'll probably
               have to rebuild the tree/MyItem's since some items
               will not appear under their parents;

               So this might look more like:

            FilteredCollection.Add( new MyItem()
                                    {
                                       Color = item.Color,
                                       Label = item.Label 
                                    } );
            */
        }
    }
}

It is possible to set a filter predicate for all nodes of a treeview hierarchy.可以为 treeview 层次结构的所有节点设置过滤谓词。 Below I am providing an extension method you can call to set the filter function like this: myTreeView.Filter(FilterPredicate);下面我提供了一个扩展方法,您可以调用它来设置过滤器 function,如下所示: myTreeView.Filter(FilterPredicate); . . Of course in the filter predicate you need to distinguish between the different types of treeview nodes of your hierarchical data model.当然在过滤谓词中你需要区分你的分层数据model的不同类型的treeview节点。

Your predicate could look like this:您的谓词可能如下所示:

private bool FilterPredicate(object node) {
  if (node is Students) {
    return true; // always show nodes of level 0
  }
  else if (node is Student) {
    return (node as Student).Name.StartsWith(_searchText);
  }
  return true;
}

Here is the extension method on TreeViewItem to set the filter on all TreeViewItems of the hierarchy recursively:这是 TreeViewItem 上的扩展方法,用于递归地在层次结构的所有 TreeViewItems 上设置过滤器:

public static class TreeViewExtensions {
    /// <summary>
    /// Applies a search filter to all items of a TreeView recursively
    /// </summary>
    public static void Filter(this TreeView self, Predicate<object> predicate)
    {
        ICollectionView view = CollectionViewSource.GetDefaultView(self.ItemsSource);
        if (view == null)
            return;
        view.Filter = predicate;
        foreach (var obj in self.Items) {
           var item = self.ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;
           FilterRecursively(self, item, predicate);
        }
    }

    private static void FilterRecursively(TreeView tree, TreeViewItem item, Predicate<object> predicate)
    {
        ICollectionView view = CollectionViewSource.GetDefaultView(item.ItemsSource);
        if (view == null)
            return;
        view.Filter = predicate;
        foreach (var obj in item.Items) {
           var childItem = tree.ItemContainerGenerator.ContainerFromItem(obj) as TreeViewItem;
           FilterRecursively(tree, childItem, predicate);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM