Search in listbox with wpf

10,715

Solution 1

Please take a look at CollectionViewSource

1) Create a CollectionViewSource:

private readonly CollectionViewSource viewSource = new CollectionViewSource();

2) Set your list as the Source:

viewSource.Source = list;

3) Set your viewsource on your ListView.

4) When you have done this, you can use the Filter property:

viewSource.Filter = FilterResults;


private bool FilterResults(object obj)
{
    //match items here with your TextBox value.. obj is an item from the list    
}

5) Finally place the refresh method of the viewSource on your TextChanged of your filter TextBox:

 void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
    viewSource.Refresh();
}

Hope this helps!

Solution 2

You can do this in your ViewModel as well.

First, bind your TextBox to a property in your view model. Make sure in your XAML that you set the UpdateSourceTrigger to PropertyChanged so you get updates on each keystroke.

Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

In your viewmodel, set up your property and your CollectionView:

    ICollectionView ViewFilter;


    private string _Filter;

    public string Filter
    {
        get { return _Filter; }
        set
        {
            _Filter = value;
            RaisePropertyChanged("Filter");
        }
    }

In your constructor, wire up the view, and monitor the propertychanged event:

        ViewFilter = CollectionViewSource.GetDefaultView(AvailableQuestion);

        ViewFilter.Filter = delegate(object item)
        {
            AvailableQuestion q = item as AvailableQuestion;
            // Check the value and return true, if it should be in the list
            // false if it should be exclucdd.

        };


        this.PropertyChanged += ((src, evt) =>
        {
            switch(evt.PropertyName)
            {
                case "Filter":
                    ProjectFilter.Refresh();
                    break;
            }

Solution 3

Here is a custom control that I made with which you can filter any ItemsControls encapsulating any type of collection of any type of objects. It's better than to keep your code behind clean : it is fulling XAML decalrative and "binding" compliant ;)

http://dotnetexplorer.blog.com/2011/04/07/wpf-itemscontrol-generic-staticreal-time-filter-custom-control-presentation/

You can find code source with example (more posts to come which will go deeper into the component)

The advantage is that you don't have to care about the collection view Management and thus poluate your vewmodel with UI concerns (because you must face the truth : even if it is done in view model, filtering a collection a mainly a UI concerns an thus better not to be in the VM). At least, put that logic in a behavior ;)

Here is the only thing you would need to have a working filter on your listbox/listview :

<SmartSearch:SmartSearchRoot x:Name="ss2"    Margin=" 10,0,10,0" >
  <SmartSearch:SmartSearchScope DataControl="{Binding ElementName=YOUR_LISTVIEW_NAME}"  UnderlyingType="{x:Type YOUR_NAMESPACE:YOUR_OBJECT_TYPE}">
     <!-- The list of property on which you want to apply filter -->                    
     <SmartSearch:PropertyFilter FieldName="YOUR_PROPERTY_ONE"  />
     <SmartSearch:PropertyFilter FieldName="YOUR_PROPERTY_TWO" MonitorPropertyChanged=""true"  />
  </SmartSearch:SmartSearchScope>
</SmartSearch:SmartSearchRoot>
Share:
10,715
Ruben
Author by

Ruben

Updated on June 04, 2022

Comments

  • Ruben
    Ruben almost 2 years

    i have a listview, binded with an observable collection of objects. Here the objects are "questions". I want to implement a sort of search engine. In textbox or something. But i have 3 columns. 1 of description, 1 of shortname and 1 of the type of the question. Here is the code of my listview :

     <ListView IsTextSearchEnabled="True"  TextSearch.TextPath="Description" ScrollViewer.CanContentScroll="True" SelectedItem="{Binding Path=SelectedQuestionDragList, UpdateSourceTrigger=PropertyChanged,Mode=OneWayToSource}" dd:DragDrop.IsDragSource="True" 
      dd:DragDrop.IsDropTarget="False"  Margin="0,34,393,333" Background="#CDC5CBC5" ScrollViewer.VerticalScrollBarVisibility="Visible"
                     dd:DragDrop.DropHandler="{Binding}" Name="listbox1" Height="155"  ItemsSource="{Binding AvailableQuestions}" SelectionChanged="listbox1_SelectionChanged">
                <ListView.View>
                    <GridView>
                        <GridView.Columns>
                            <GridViewColumn Header="Verkorte naam" Width="Auto" DisplayMemberBinding="{Binding Path=ShortName}" />
                            <GridViewColumn Header="Omschrijving" Width="Auto" DisplayMemberBinding="{Binding Path=Description}" />
                            <GridViewColumn Header="Type" Width="Auto" DisplayMemberBinding="{Binding Path=Type}" />
                        </GridView.Columns>
                    </GridView>
                </ListView.View>
            </ListView>
    

    I have tried already a lot of things. But i just want to keep one simple thing: a textbox ,and if you fill in there some letters, the program has to filter where this combination of letters is exists. Someone who knows a simple solution or example?

    Thanks!

  • Ruben
    Ruben about 13 years
    but this is all in the code behind i suppose? i am trying to keep my code behind clean and works with MVVM.. An idea about how to do that?
  • Robaticus
    Robaticus about 13 years
    @Ruben, check out my answer for how to do this in your VM.
  • Ruben
    Ruben about 13 years
    So i have to put the second part (ViewFilter = CollectionViewSource.GetDefaultView(AvailableQuestion); .....) in my constructor of my viewmodel?
  • Arcturus
    Arcturus about 13 years
    Either way works.. the key here is the CollectionViewSource, either by creating it, or using the default.
  • Robaticus
    Robaticus about 13 years
    Yes, that needs to be put in the constructor.
  • Robaticus
    Robaticus about 13 years
    yes. The CollectionViewSource is awesome for filtering, sorting, etc, without having to mess with the underlying collection.
  • Webbarr
    Webbarr almost 4 years
    I know this was quite some time ago - but the link is now returning a 500 message. Any chance that is hosted somewhere else?