I have a ListBox with binding to a list of strings. I want to filter the list when I enter text in a TextBox. How can I do it?
public void ListLoad()
{
ElementList = new List<string>(); // creation a list of strings
ElementList.Add("1"); // add a item of string
ElementList.Add("2"); // add a item of string
DataContext = this; // set the data context
}
I'm binding it in XAML with:
ItemsSource="{Binding ElementList}"
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
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;
}
}
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".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With