WPF Filter a ListBox

CollectionViewSource class can help here. As far as I can tell it has many capabilities to filter, sort and group collections.

ICollectionView view = CollectionViewSource.GetDefaultView(ElementList);
view.Filter = (o) => {return o;}//here is the lambda with your conditions to filter

When you don't need any filter just set view.Filter to null. Also check out this article on filtering


If you set Dictionary as itemsource to listbox use the below code to sort,

    private void tb_filter_textChanged(object sender, TextChangedEventArgs e)
    {
        Dictionary<string, string> dictObject = new Dictionary<string, string>();
        ICollectionView view = CollectionViewSource.GetDefaultView(dictObject);
        view.Filter = CustomerFilter;
        listboxname.ItemsSource = view;
    }

    private bool CustomerFilter(object item)
    {
        KeyValuePair<string, string> Items = (KeyValuePair<string,string>) item;
        return Items.Value.ToString().Contains("a");
    }

The above code returns the items contaning "a".


Here is an attached property for binding a filter:

using System;
using System.Windows;
using System.Windows.Controls;

public static class Filter
{
    public static readonly DependencyProperty ByProperty = DependencyProperty.RegisterAttached(
        "By",
        typeof(Predicate<object>),
        typeof(Filter),
        new PropertyMetadata(default(Predicate<object>), OnByChanged));

    public static void SetBy(ItemsControl element, Predicate<object> value)
    {
        element.SetValue(ByProperty, value);
    }

    public static Predicate<object> GetBy(ItemsControl element)
    {
        return (Predicate<object>)element.GetValue(ByProperty);
    }

    private static void OnByChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is ItemsControl itemsControl &&
            itemsControl.Items.CanFilter)
        {
            itemsControl.Items.Filter = (Predicate<object>)e.NewValue;
        }
    }
}

Used like this in xaml:

<DataGrid local:Filter.By="{Binding Filter}"
          ItemsSource="{Binding Foos}">
    ...

And viewmodel:

public class ViewModel : INotifyPropertyChanged
{
    private string filterText;
    private Predicate<object> filter;

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Foo> Foos { get; } = new ObservableCollection<Foo>();

    public string FilterText
    {
        get { return this.filterText; }
        set
        {
            if (value == this.filterText) return;
            this.filterText = value;
            this.OnPropertyChanged();
            this.Filter = string.IsNullOrEmpty(this.filterText) ? (Predicate<object>)null : this.IsMatch;
        }
    }

    public Predicate<object> Filter
    {
        get { return this.filter; }
        private set
        {
            this.filter = value;
            this.OnPropertyChanged();
        }
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private bool IsMatch(object item)
    {
        return IsMatch((Foo)item, this.filterText);
    }

    private static bool IsMatch(Foo item, string filterText)
    {
        if (string.IsNullOrEmpty(filterText))
        {
            return true;
        }

        var name = item.Name;
        if (string.IsNullOrEmpty(name))
        {
            return false;
        }

        if (filterText.Length == 1)
        {
            return name.StartsWith(filterText, StringComparison.OrdinalIgnoreCase);
        }

        return name.IndexOf(filterText, 0, StringComparison.OrdinalIgnoreCase) >= 0;
    }
}