Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter a collection when binding it to ItemsSource?

I created a treeview which modelizes directories and files on my hard drive. Each treeviewItem has a checkbox, binded to a isSelected property. What I'd like to achieve is display for each parent node the count of selected files on the total files count (10 / 12 10 files on twelve total selected).

Is there a way to do a binding with where property is ...?

<ContentPresenter Content="{Binding MyItems.Count where MyItems.IsSelected, Mode=OneTime}"
                  Margin="2,0" />
like image 283
G. Abitbol Avatar asked Apr 18 '13 06:04

G. Abitbol


People also ask

What is WPF CollectionViewSource?

CollectionViewSource is a proxy for a CollectionView class, or a class derived from CollectionView. CollectionViewSource enables XAML code to set the commonly used CollectionView properties, passing these settings to the underlying view.


1 Answers

There is no way to directly filter the collection in the binding. However, WPF allows filtering (and sorting and grouping) collections with CollectionViewSource.

One approach would be to define a CollectionViewSource in the resources of your ItemTemplate which filters the ItemsSource an get the number of elements which pass the filter by binding to the Count property of this CollectionViewSource. You have to define your filter in codebehind, though. Would look something like this:

<TreeView x:Name="Tree" ItemsSource="{Binding Items}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">
            <HierarchicalDataTemplate.Resources>
                <CollectionViewSource x:Key="FilteredItems" 
                                        Source="{Binding ChildItems}"
                                        Filter="FilteredItems_OnFilter" />
            </HierarchicalDataTemplate.Resources>
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding StringFormat="{} {0} of {1} selected">
                        <Binding Path="Count" Source="{StaticResource FilteredItems}" />
                        <Binding Path="ItemsSource.Count" ElementName="Tree" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

And in the codebehind:

private void FilteredItems_OnFilter(object sender, FilterEventArgs e)
{
    var item = sender as Item;
    e.Accepted = item.IsSelected;
}

I haven't tested it but it should work in general. You never know with WPF, though...

like image 187
Marc Avatar answered Nov 07 '22 02:11

Marc