WPF: Filtern im DataGrid mit CollectionViewSource

Veröffentlicht von

Filtern von Daten in WPF-Controls mit der CollectionViewSource, ein Beispiel.

Unser Ziel ist folgende Anwendung. Ein DataGrid, kann auch jedes andere Control sein, welches eine Liste aufnimmt, soll Daten darstellen und eine Filterung der Daten erlauben.

Unser Filter ist einfach, kommt der String im Namen vor, dann wird der Wert der Liste angezeigt, ansonsten halt nicht.

Unsere Datenklasse sieht wie folgt aus:

public class Drinker
{
    public string Name { get; set; }
    public string FavoriteBeer { get; set; }
    public string LeastFavoriteBeer { get; set; }
}

Im ViewModel haben wir eine einfache Liste:

public ObservableCollection Drinkers { get; } = new ObservableCollection();

Ein paar Testdaten:

var d1 = new Drinker {Name = "Andy", FavoriteBeer = "Jever", LeastFavoriteBeer = "Becks"};
var d2 = new Drinker {Name = "Kiwi", FavoriteBeer = "Lübzer", LeastFavoriteBeer = "Ötti Light"};
var d3 = new Drinker {Name = "Ebe", FavoriteBeer = "Augustiner", LeastFavoriteBeer = "Öttinger"};
var d4 = new Drinker {Name = "Wolfram", FavoriteBeer = "Dein Bier", LeastFavoriteBeer = "Heinken"};

Drinkers.Add(d1);
Drinkers.Add(d2);
Drinkers.Add(d3);
Drinkers.Add(d4);

Binden wir direkt an die Liste, dann wird alles angezeigt, wir wollen aber selbst entscheiden, was angezeigt wird und was nicht. Hier kommt die CollectionViewSource ins Spiel. Diese legen wir als Property im ViewModel an:

public CollectionViewSource ViewSource { get; set; } = new CollectionViewSource();

Der CollectionViewSource weisen wir jetzt unsere Daten zu:

ViewSource.Source = Drinkers;
ViewSource.Filter += ViewSource_Filter;

Zusätzlich legen wir gleich noch den Filter fest, dazu später mehr.

Zuerst brauchen wir noch ein Property für unseren Suchtext:

private string _filterText;

public string FilterText
{
    get => _filterText;
    set
    {
        if (value != _filterText)
        {
            _filterText = value;
            OnPropertyChanged(nameof(FilterText));
            ViewSource.View.Refresh();
        }
    }
}	

Dieser wird mit der TextBox im Xaml verbunden und löst auch gleich einen Refresh auf die CollectionViewSource aus. Der Refresh ist dann auch der Punkt an welchem wir in die Filterung eingreifen können. Wir hatten der CollectionViewSource ja bereits das Filter-Event zugewiesen. Hier können wir nun für jedes Item entscheiden, ob es angezeigt werden soll oder nicht:

private void ViewSource_Filter(object sender, FilterEventArgs e)
{
    bool accept = true;

    var item = (Drinker) e.Item;

    if (_filterText != "")
    {
        accept = item.Name.Contains(_filterText);
    }

    e.Accepted = accept;
}

Über “e.Item” kommen wir an das aktuelle Datenobjekt. Mittels e.Accepted können wir entscheiden, ob das Element angezeigt werden soll oder nicht.

Download des Beispielprojekts

2 Kommentare

  1. Hallo,
    bin neu in der WPF/C# Programmierung.
    Eine Gruppierung per CollectionView habe ich hinbekommen, beim Filter habe ich einige Probleme.
    Meine Daten kommen aus einem DataSet, CollectionView für Datenübergaben ist auch vorhanden.
    So wie ich das sehe, wir hier explizit nach Name gefiltert?
    Wie müsste der Code aussehen, wenn ich alle Columns durchsuchen will?

    1. Genau ich filtere hier nur nach dem Namen:
      accept = item.Name.Contains(_filterText);

      Du kannst das natürlich auch erweitern um weitere Eigenschaften:
      if (item.Name.Contains(_filterText) && (item.AndereEigenschaft.Contains(_filterText))
      {
      accept = true;
      }

      Im Prinzip hast Du Freiheiten das Datenobjekt für jede Zeilen abzufragen und dann zu entscheiden, ob es angezeigt wird.

Kommentar hinterlassen

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