简体   繁体   中英

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:

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. For example, Class A with red node, because Student 3 it's node was red color.

在此处输入图像描述

How to implement filter tree view function in WPF c#?

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 Sample

Main 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).

So, whenever you're binding to an ItemsSource for the TreeView, you'll need to be binding to the FilteredObservableCollection. By default, this collection will be initialized with ALL of the items in the 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. You would clear ALL items from the FilteredObservableCollection and then loop through the MasterObservableCollection, adding the items that match the criteria into it.

So, some brief pseudo-code from your 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. Below I am providing an extension method you can call to set the filter function like this: 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.

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:

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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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