使用 ICollectionView 多次过滤集合

发布于 2024-12-06 06:10:12 字数 442 浏览 2 评论 0原文

我正在尝试过滤 DataGrid 中显示的 ObservableCollection。 第一次效果很好,但是当我再次尝试过滤时,它使用源集合而不是过滤结果。 简短的代码示例:

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);
view.Filter = delegate(object item){
  User user = item as User;
  if(user != null && user.Name.ToLower().Contains(textbox.Text.ToLower())) return true;
  return false;
};

所以我想要做的是仅过滤 DataGrid 中显示的项目,而不是整个集合(当然,第一次使用过滤器时,它将使用整个集合)。

I'm trying to filter an ObservableCollection that is displayed in a DataGrid.
This works great the first time, but when I try to filter again, it uses the sourcecollection instead of the filtered result.
Short code example:

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);
view.Filter = delegate(object item){
  User user = item as User;
  if(user != null && user.Name.ToLower().Contains(textbox.Text.ToLower())) return true;
  return false;
};

So what I want to do is filter only the items that are shown in my DataGrid, and NOT the entire collection (of course the first time that the filter is used, it will use the entire collection).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苏大泽ㄣ 2024-12-13 06:10:12

另一种选择是这样的...

public void cmbYourComboBox_SelectionChanged(object sender, RoutedEventArgs e)
{
    ICollectionView filteredView = CollectionViewSource.GetDefaultView(collection);

    filteredView.Filter = new Predicate<object>(GetFilteredView);

    dgYourDataGrid.ItemsSource = filteredView;
}

public bool GetFilteredView(object sourceObject)
{
    if (HasConditionOne(sourceObject) && HasConditionTwo(sourceObject)
    {
        return true;
    }
    return false;
}

public bool HasConditionOne(object sourceObject)
{
    //perform your test and evaluate the outcome
}

public bool HasConditionTwo(object sourceObject)
{
    //perform your test and evaluate the outcome
}

如果源对象满足所有必需的条件,它将被认为适合在过滤视图中显示。

Another option would be something like...

public void cmbYourComboBox_SelectionChanged(object sender, RoutedEventArgs e)
{
    ICollectionView filteredView = CollectionViewSource.GetDefaultView(collection);

    filteredView.Filter = new Predicate<object>(GetFilteredView);

    dgYourDataGrid.ItemsSource = filteredView;
}

public bool GetFilteredView(object sourceObject)
{
    if (HasConditionOne(sourceObject) && HasConditionTwo(sourceObject)
    {
        return true;
    }
    return false;
}

public bool HasConditionOne(object sourceObject)
{
    //perform your test and evaluate the outcome
}

public bool HasConditionTwo(object sourceObject)
{
    //perform your test and evaluate the outcome
}

If the source object satisfies all of the required conditions it will be deemed appropriate for display in the filtered view.

赠我空喜 2024-12-13 06:10:12

您应该解决的真正问题是 CollectionView Filter 的性能,而不是通过将新过滤的列表作为源集合反馈到下一个过滤器来实现嵌套过滤器。

当用户多次尝试键入和删除字符时,您“想要”的嵌套过滤器/反馈源集合方法将导致问题,因为这样您将不确定哪个源集合适用于该过滤器文本。

例如,我们有 100 名员工,我们通过输入“员工姓名”为“A”来对其进行过滤...这列出了 50 名姓名以“A”开头的员工。现在我们继续输入“H”...从这 50 名姓名以“AH”开头的员工中过滤出 10 名员工。但现在我们删除“H”,理想情况下它应该使用 100 名员工来搜索新的员工列表,但它会使用 10 名员工,因为这会反馈到嵌套过滤过程。

想象一下,如果有人经常键入并从过滤的文本中删除随机字符,事情会变得多么复杂!

所以基本规则是您必须在整个源集合中进行过滤

一旦我们现在知道了这一点我们可以尝试改进过滤功能...

  1. 使用 LINQ 并将结果设置到每个键入的字符上的 DataGrid 的 ItemsSource。它们非常适合大型集合(我有一个这样的数据网格,有 30 万行,我使用 LINQ 来执行快速过滤)。

  2. LINQ 可以在后台线程上运行,并将结果重新应用到数据网格的 ItemsSource。

  3. 如果在 .Net 4.0 中,LINQ 提供 AsParallel() 调用。非常有效。使用有限数量的池线程进行过滤。

  4. LINQ 还为基于字符串属性名称的搜索提供 AsQueryable() 接口。

The real problem you should be fixing is the performance of CollectionView Filter, instead of implementing nested filters by feeding back the newly filtered list as source collection to next filter.

The nested filter / feedback source collection method that you "want", will cause issues when user performs several attempts of typing and removing characters because then you will not be sure which source collection applies to that filter text.

E.g. We have 100 employees and we filter it by typing "Employee Name" as "A"... This lists 50 employees with names starting with "A". Now we continue to type "H"... 10 employess from those 50 having names starting with "AH" are filtered. But now we remove "H", ideally it should use 100 employees to search new list of employees but it will use 10 employees as that is fed back to the nested filtering process.

Imagine how complicated it will get if someone frequently types and removes random characters from the filtered text!

So ground rule is You must filter in the entire source collection

Once we know this now we can try to improve the filter functionality...

  1. Use LINQ and set the result to the ItemsSource of the DataGrid on each typed character. They work great for large collections (I had one such datagrid having 300 thousand rows and I used LINQ to perform fast filtering).

  2. LINQ can run on a background thread and reapply result to the ItemsSource of the datagrid.

  3. If in .Net 4.0, LINQ offers AsParallel() calls. Very effective. Uses limited number of pooled threads for filtering.

  4. LINQ also offers AsQueryable() interface for string property name based search.

随心而道 2024-12-13 06:10:12

其他东西(可能是DataGrid)可能会重置您视图上的过滤器,因为您使用的是共享的默认视图。请改用您自己的集合视图:

ICollectionView view = new ListCollectionView(myList);

Something else (likely the DataGrid) may be resetting the filter on your view, since you're using the default view which is shared. Use your own collection view instead:

ICollectionView view = new ListCollectionView(myList);
陈独秀 2024-12-13 06:10:12

您可以创建一个辅助方法,检查您是否已经在集合上设置了过滤器,如果已经设置,则将过滤后的列表保存在视图中并再次过滤它,并将视图设置为 DataGrid 的数据源。

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);

我认为这部分代码总是为您提供整个集合,而不是已经过滤的集合。

You could create a helper method which checks is you already set a Filter on the collections and if it is already set then you save your filtered list in a view and filter it again and set the view as the datasource of your DataGrid.

ICollectionView view = CollectionViewSource.GetDefaultView(myCollection);

And i think this part of code gives you always the whole collection and not the already filtered one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文