Фильтр DataGrid в WPF

я загружаю списки объектов в datagrid с этим:

dataGrid1.Items.Add(model);

на model стать данные из базы данных. У него есть Id(int), Name(string) и Text(string)

в моем datagrid я показываю только имя model. Как я могу фильтровать datagrid сейчас, когда я ввожу что-то в текстовое поле?

Я был на этой странице:http://msdn.microsoft.com/en-us/library/vstudio/ff407126 (v=против 100).aspx но я не понимаю код оттуда, и я не могу объясните, как я должен перенести это для моей проблемы.

5 ответов


существует несколько способов фильтрации коллекции

давайте предположим, что это ваш класс элемента

public class Model
{
    public string Name
    {
        get;
        set;
    }
}

и ваша коллекция выглядит так:

       var ObColl = new ObservableCollection<Model>();

        ObColl.Add(new Model() { Name = "John" });
        ObColl.Add(new Model() { Name = "Karl" });
        ObColl.Add(new Model() { Name = "Max" });
        ObColl.Add(new Model() { Name = "Mary" });

Способ 1 (Сказуемое):

    public MainWindow()
    {
        InitializeComponent();

        // Collection which will take your ObservableCollection
        var _itemSourceList = new CollectionViewSource() { Source = ObColl };

        // ICollectionView the View/UI part 
        ICollectionView Itemlist = _itemSourceList.View;

        // your Filter
        var yourCostumFilter= new Predicate<object>(item => ((Model)item).Name.Contains("Max"));

        //now we add our Filter
        Itemlist.Filter = yourCostumFilter;

        dataGrid1.ItemsSource = Itemlist;
    }

Способ 2 (FilterEventHandler):

    public MainWindow()
    {
        InitializeComponent();

        // Collection which will take your Filter
        var _itemSourceList = new CollectionViewSource() { Source = ObColl };

       //now we add our Filter
       _itemSourceList.Filter += new FilterEventHandler(yourFilter);

        // ICollectionView the View/UI part 
        ICollectionView Itemlist = _itemSourceList.View;

        dataGrid1.ItemsSource = Itemlist;
    }

    private void yourFilter(object sender, FilterEventArgs e)
    {
        var obj = e.Item as Model;
        if (obj != null)
        {
            if (obj.Name.Contains("Max"))
                e.Accepted = true;
            else
                e.Accepted = false;
        }
    }

расширенная информация к способу 1

если нужно несколько условий или какой-то сложный фильтр, вы можете добавить метод в свой Predicat

    // your Filter
    var yourComplexFilter= new Predicate<object>(ComplexFilter);

    private bool ComplexFilter(object obj)
    {
        //your logic
    }

это простая реализация использования свойства фильтра ICollectionView. Предположим, ваш XAML содержит следующее:

<TextBox x:Name="SearchTextBox" />
<Button x:Name="SearchButton"
        Content="Search"
        Click="SearchButton_OnClick"
        Grid.Row="1" />
<DataGrid x:Name="MyDataGrid"
          Grid.Row="2">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Lorem ipsum column"
                            Binding="{Binding}" />
    </DataGrid.Columns>
</DataGrid>

затем в конструкторе вы можете получить представление по умолчанию для ваших данных, где вы можете установить предикат фильтра, который будет выполняться для каждого элемента вашей коллекции. CollectionView не будет знать, когда он должен обновить коллекцию, поэтому вам нужно вызвать обновление, когда пользователь нажимает кнопку поиска.

private ICollectionView defaultView;

public MainWindow()
{
    InitializeComponent();

    string[] items = new string[]
    {
        "Asdf",
        "qwer",
        "sdfg",
        "wert",
    };

    this.defaultView = CollectionViewSource.GetDefaultView(items);
    this.defaultView.Filter =
        w => ((string)w).Contains(SearchTextBox.Text);

    MyDataGrid.ItemsSource = this.defaultView;
}

private void SearchButton_OnClick(object sender, RoutedEventArgs e)
{
    this.defaultView.Refresh();
}

по этому url вы можете найти более подробное описание CollectionViews: http://wpftutorial.net/DataViews.html


@WiiMaxx, не может комментировать как недостаточно респ. Я был бы немного более осторожен с прямыми слепками. Они могут быть медленными для одного и для другого, если тот же фильтр был применен к сетке, содержащей данные другого сложного типа, у вас будет InvalidCastException.

// your Filter
    var yourCostumFilter= new Predicate<object>(item =>
    {
        item = item as Model;
        return item == null || item.Name.Contains("Max");
    });

Это не сломает вас datagrid и не будет фильтровать результаты, если приведение не удастся. Меньше влияния на ваших пользователей, если вы получите код неправильно. Кроме того, фильтр будет быстрее из-за " as" оператор не делает никакого явного принуждения типа, как будет операция прямого приведения.


посмотрите на привязку данных --> в вашем случае не добавляйте элементы в сетку, но установите itemssource

<Datagrid ItemsSource="{Binding MyCollectionOfModels}" />

или

dataGrid1.ItemsSource = this._myCollectionOfModels;

и если вы хотите какую-то фильтрацию,сортировку, группировку, посмотрите на CollectionView


для фильтрации строк datagrid можно использовать фильтр dataview.

            DataView dv = datatable.DefaultView;

            StringBuilder sb = new StringBuilder();
            foreach (DataColumn column in dv.Table.Columns)
            {
                sb.AppendFormat("[{0}] Like '%{1}%' OR ", column.ColumnName, "FilterString");
            }
            sb.Remove(sb.Length - 3, 3);
            dv.RowFilter = sb.ToString();
            dgvReports.ItemsSource = dv;
            dgvReports.Items.Refresh();

где "datatable" - это источник данных, заданный вашему datagrid, и с помощью строкового построителя вы создаете запрос фильтра, где" строка фильтра " - это текст, который вы хотите найти в своем datagrid, и установите его в dataview и, наконец, установите dataview как itemsource в свой datagrid и обновите его.