在WPF中过滤DataGrid

22

我用以下代码将对象列表加载到数据网格中:

dataGrid1.Items.Add(model);

model 是从数据库获取的数据。它有一个 Id(int)Name(string)Text(string)

在我的 datagrid 中,我只显示 model 的名称。现在当我输入文本框时,如何过滤 datagrid?

我看了这个页面:http://msdn.microsoft.com/en-us/library/vstudio/ff407126(v=vs.100).aspx 但我不理解那里的代码,也无法说明该如何将其应用到我的问题上。


请告诉我们您的具体问题。您创建的代码是什么?我们可以告诉您其中的问题所在。 - Loránd Biró
我不明白如何使用CollectionViewSource解决我的问题。你能否解释一下如何在我的DataGrid中使用“collection…”加载数据以及如何进行筛选?@Kylerrr - Karl_Schuhmann
7个回答

53

有多种方法可以过滤集合。

假设这是您的项目类。

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" });

第一种方式(谓词):

    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的扩展信息

如果需要多个条件或一些复杂的筛选,您可以向Predicate中添加一个方法。

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

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

你好,我有一个类似的问题.. 你能不能看一下这篇文章告诉我是否这是正确的做法?这将非常有帮助。谢谢 :) - http://stackoverflow.com/questions/15569445/display-datagrid-details-from-the-combobox-selecteditem/15579909?noredirect=1#15579909 - Indhi
我想看看针对当前情况最合适的方法,有什么建议吗?能否在你的答案中加入这个建议?如果你这样做,就会有一个很酷的+1等着你... :) - Konrad Viltersten
1
@KonradViltersten 嗯,我会说这取决于你的喜好。如果你喜欢使用事件,请使用 FilterEventHandler;如果你更喜欢对象,请使用 Predicate 解决方案。我也不得不承认,我对性能差异一无所知。 - WiiMaxx

9
这是使用ICollectionView的Filter属性的简单实现。假设你的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不知道何时应更新集合,因此当用户单击搜索按钮时,您必须调用Refresh。

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();
}

在此网址中,您可以找到有关CollectionView的更详细描述: http://wpftutorial.net/DataViews.html

5

@WiiMaxx,由于声望不够,我无法发表评论。关于直接强制转换,我建议您要更加谨慎。它们可能会很慢,如果将相同的过滤器应用于包含不同复杂类型数据的网格,则可能会引发InvalidCastException异常。

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

这不会破坏您的数据网格,并且如果转换失败,也不会过滤结果。如果您的代码有误,对用户的影响较小。此外,由于“as”运算符不执行任何显式类型转换,因此筛选速度更快。


3
我测试了你的代码,但无法编译。你需要写成 var model = item as Model; 并在逻辑中使用 model,这样就可以正常工作了。 - WiiMaxx

0
您可以使用数据视图过滤器来过滤数据网格行。
            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"是提供给数据网格的数据源,在使用字符串构建器构建筛选查询时需要使用"Filter String"作为你想要在数据网格中搜索的文本,并将其设置为dataview,最后将dataview设置为你的数据网格的itemsource并刷新它。


0

如果像我一样,您无法使上述方法正常工作,请将此留在这里。

//Example of my Transaction class
//Transaction(ID, Amount, Description)

ListCollectionView collectionView = new ListCollectionView(List<Transaction>);
collectionView.Filter = (e) =>
{
    Transaction transaction = e as Transaction;
    if (transaction.Amount >= 0) //When this is true it returns all positive transactions
    {
       return true;
    }
    else
    {
       return false;
    }
};

dataGrid.ItemsSource = collectionView;

  • 我在if语句中使用了这个,以便为数据网格创建一个下拉框筛选器。
  • 下拉框有3个选项:借记/贷记/借记和贷记,根据我选择的选项,在选择更改事件上进行筛选
  • 我从这里得到了这个:http://dotnetpattern.com/wpf-datagrid-filtering

0

我发现了一种愚蠢的方法,知道这是一个老问题,但是...只需在DataGrid对象上使用items属性上的Filter函数。像这样:(对不起,我只学会了VB)

Public Property SearchName As String
    Get
        Return _SearchName
    End Get
    Set
        _SearchName = Value
        DG_drw_overview.Items.Filter = New Predicate(Of Object)(Function(x) x.Name.Contains(Value))           
    End Set
End Property

每次在文本框中输入内容时,此属性都会更改。DG_drw_overview是DataGrid实例。在Predicate中,该对象表示您放入DataGrid中的对象。

然后将SearchName绑定到文本框

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

将文本框的数据上下文设置为主类(通常在InitializeComponent()之后)

TB_search.DataContext = Me

0

看一下数据绑定 --> 在你的情况下,不要向网格添加项目,而是设置项目源

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

或者

dataGrid1.ItemsSource = this._myCollectionOfModels;

如果您需要某种过滤、排序、分组功能,请查看CollectionView


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接