CollectionViewSource in WPF, Filtern von Daten in Listen

Veröffentlicht von

Mit der CollectionViewSource können Elemente in ListBoxen, ListViews und anderen grafischen GUI-Elementen leicht umgesetzt werden.

Eine ObservableCollection lässt sich an ein ListView zur Darstellung der Elemente binden. Doch wie kann man die Liste filtern? Hier steht mit der CollectionViewSource ein Proxy zur Verfügung, welcher uns dies erlaubt. Dir binden die Liste nicht mehr direkt an das GUI-Element, sondern die CollectionViewSource.

Schauen wir unser Ziel an:

Eine Liste von Elementen. Über ein Suchfeld wollen wir über den Anfang des Namens oder der favorisierten Biersorte filtern.

Wie gehen wir vor? Hinweis: Das ganze Projekt gibt es am Ende zum Download.

Fangen wir mit der Liste der Personen an:

private ObservableCollection _listPersons = new ObservableCollection();

_listPersons.Add(new Person() { Name = "Ebe", FavoriteBeer = "Augustiner" });            
_listPersons.Add(new Person() { Name = "Andy", FavoriteBeer = "Öttinger" });
_listPersons.Add(new Person() { Name = "Herbie", FavoriteBeer = "Reischenau Gold" });
_listPersons.Add(new Person() { Name = "Erwin", FavoriteBeer = "Heineken" });
_listPersons.Add(new Person() { Name = "Wolfram", FavoriteBeer = "Dein Bier" });
_listPersons.Add(new Person() { Name = "Klaus", FavoriteBeer = "Radeberger" });
_listPersons.Add(new Person() { Name = "Kiwi", FavoriteBeer = "Meisterpils" });
_listPersons.Add(new Person() { Name = "Peter", FavoriteBeer = "Dein Bier" });

Die Listen binden wir nicht direkt an unser ListView, sondern erstellen eine CollectionViewSource:

internal CollectionViewSource PersonViewSource
{
    get; set;
} = new CollectionViewSource();

Für die Datenbindung im Xaml-Code legen wir ein Property für den Zugriff auf das View-Element der CollectionViewSource an:

public ICollectionView PersonView
{
    get { return PersonViewSource.View; }
}

Nun verbinden wir die CollectionViewSource mit unserer Liste der Daten, dies machen wir im Konstruktor unseres Fensters:

PersonViewSource.Source = _listPersons;

Im Xaml-Code legen wir jetzt unser LiewView an, für die Datenbindung verwenden wir unser Property PersonView:

<ListView x:Name="ListViewPerson"
          Grid.Column="1"
          ItemsSource="{Binding PersonView}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}"></TextBlock>
                <TextBlock Text=" - "></TextBlock>
                <TextBlock Text="{Binding FavoriteBeer}"></TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>

Das Ergebnis ist, dass wir nun bereits unsere Liste angezeigt bekommen sollten.

Filtern der Anzeige

Soweit so gut, aber nun wollen wir die Anzeige filtern. Dazu legen wir ein Property an:

private string _filterText = "";
public string FilterText
{
    get
    {
        return _filterText;
    }

    set
    {
        _filterText = value;
        NotifyPropertyChanged();
        PersonView.Refresh();
    }
}

Dies ist unser Suchtext nach dem wir filtern wollen. In der GUI legen wir dazu eine Textbox an:

<TextBox x:Name="TextBoxSearch"
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
></TextBox>

Ändert der Anwender nun den Suchtext, soll unsere PersonView einen Refresh auslösen. Was noch fehlt ist nun die Logik für die Filterung. Hierzu bietet die CollectionViewSource ein Event mit dem Namen Filter an.

PersonViewSource.Filter += PersonViewSource_Filter;

Die Implementierung:

private void PersonViewSource_Filter(object sender, FilterEventArgs e)
{
    if (string.IsNullOrWhiteSpace(_filterText))
    {
        //no filter when no search text is entered
        e.Accepted = true;
    } else
    {
        Person p = (Person)e.Item;
        if (p.Name.StartsWith(_filterText) || p.FavoriteBeer.StartsWith(_filterText))
        {
            e.Accepted = true;
        } else
        {
            e.Accepted = false;
        }
    }
}

Der Filter geht über die Liste der Elemente und bei jedem Element können wir entscheiden, ob es angezeigt wird. In unserem Beispiel wollen wir, dass alle Elemente angezeigt werden, wenn der Anwender keinen Suchtext eingegeben hat. Hat er etwas eingegeben, dann wird geschaut, ob der String als Starttext von Name oder FavoriteBeer vorkommt.

Das Ergebnis ist eine automatische Filterung. Der Vorteil: unsere unterliegende Liste bleibt komplett unbehelligt davon.

Download des Beispiels

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert