【问题标题】:Filtering and ICollectionView Filter WPF过滤和 ICollectionView 过滤器 WPF
【发布时间】:2016-04-07 21:49:59
【问题描述】:

我目前有一个DataGrid,其中包含我根据两件事过滤的公司 - 一个是用户可以根据公司名称、城镇或邮政编码过滤的搜索框。看起来像这样;

按名称/城镇/邮政编码过滤

        private void FilterDataGrid()
        {
            try
            {
                var searchText = CharactersOnly(searchBox.Text);
                CompanyICollectionView.Filter = (obj =>
                {
                    CompanyModel compDetails = obj as CompanyModel;
                    if (compDetails == null)
                    {
                        return true;
                    }

                    if (compNameRad.IsChecked == true)
                    {
                        return CompanyContains(compDetails.Name, searchText.ToLower());
                    }
                    if (compTownRad.IsChecked == true)
                    {
                        return CompanyContains(compDetails.Town, searchText.ToLower());
                    }
                    if (compPcodeRad.IsChecked == true)
                    {
                        return CompanyContains(compDetails.Postcode, searchText.ToLower());
                    }
                    return false;
                });

                if (dataGrid.Items.Count == 0) // There are no companies with this filter on, clear the label
                {
                    compDetailsLabel.Content = string.Empty;
                }
                else
                {
                    dataGrid.SelectedIndex = 0;
                }
            }
            catch (Exception ex)
            {
                var hEs = new HandleExceptionService();
                hEs.HandleException(ex.ToString());
            }
        }

第二种过滤方法是基于公司的类型。这是通过选择多个CheckBoxes 来完成的。这个方法看起来是这样的;

按公司类型过滤

    private void FilterCompanyType(object sender, RoutedEventArgs e)
    {
        criteria.Clear();

        if (currentCheckBox.IsChecked == true && nonCurrentCheckBox.IsChecked == false)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.CurrentStatus == 1));
        }
        else if (nonCurrentCheckBox.IsChecked == true && currentCheckBox.IsChecked == false)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.CurrentStatus == 0));
        }
        else if (nonCurrentCheckBox.IsChecked == true && currentCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => (x.CurrentStatus == 1 || x.CurrentStatus == 0)));
        }

        if (subbieCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.Subcontractor == 1));
        }

        if (supplierCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.Supplier == 1));
        }

        if (planthireCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.Planthire == 1));
        }

        if (architectCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.Architect == 1));
        }

        if (qsCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.QS == 1));
        }

        if (projectManagerCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.ProjectManager == 1));
        }

        if (structEngCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.StructEng == 1));
        }

        if (servEngCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.ServiceEng == 1));
        }

        foreach (CheckBox checkBox in companyFilters.Children)
        {
            if (!CheckCheckBoxes())
            {
                dataGrid.ItemsSource = null;
                compDetailsLabel.Content = string.Empty;
            }
            else
            {
                dataGrid.ItemsSource = CompanyICollectionView;
                CompanyICollectionView.Filter = dynamic_Filter;
                SetSelectedCompany(selectedIndex);
                dataGrid.SelectedIndex = 0;
            }
        }

        var nfi = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
        nfi.NumberGroupSeparator = ",";
        numberOfCompaniesLabel.Content = "Number of Companies: " + dataGrid.Items.Count.ToString("#,#", nfi);
    }

这两种过滤方法本身看起来都很好。当我想过滤已应用于 DataGrid 的过滤器时,问题就出现了。例如,用户想要筛选出公司类型,因此他们选择了currentCheckBoxsupplierCheckBoxsubbieCheckBox。这将返回所有当前也是分包商的供应商。

这仍然会返回一个包含 5000 家公司的列表,因此用户想要使用搜索功能来查找他们知道名称的公司。但它不会搜索过滤后的CompanyICollection,它会重置它并过滤整个列表(27000 家公司)。

我认为问题在于,当我想搜索现有的 CompanyICollectionView.Fiilter 时,我每次都在创建一个新的 CompanyICollectionView.Fiilter。有没有办法过滤已经过滤的ICollectionView

编辑(添加动态过滤器)

        private bool dynamic_Filter(object item)
        {
            CompanyModel company = item as CompanyModel;
            bool isIn = true;
            if (criteria.Count() == 0)
                return isIn;
            isIn = criteria.TrueForAll(x => x(company));
            return isIn;
        }

【问题讨论】:

  • 两个过滤器是否使用相同的项目来源?
  • DataGrid 具有相同的ItemsSource 是的,(CompanyICollectionView)
  • 您的dynamic_Filter 来自哪里?从criteria创建?
  • 添加即编辑

标签: c# wpf filter datagrid


【解决方案1】:

无需在每次属性更改时重新创建过滤器。 最适合您的做法是将两个过滤器组合在一个函数中,将其传递给CompanyICollectionView.Filter,并从属性更改事件中调用CompanyICollectionView.Refresh();。 您甚至可以将您的 collectionview 绑定到支持过滤的 ObservableCollection,即 FilteredObservableCollection... 看一下: CollectionViewSource Filter not refreshed when Source is changed

【讨论】:

    【解决方案2】:

    你是对的,问题是你每次都在重置过滤器。所以你需要做一些修改来解决你的问题(我会假设所有的代码都在同一个类中):

    private bool filterCompanyInfos(object o){
        //Function which return true if selected info and filter (name, town, code,...) corresponds to the object o (casted as a CompanyModel)
        //I let you write this part, should be like the filterCompanyType method.
    }
    
    private bool filterCompanyType(object o){
        criteria.Clear();
    
        if (currentCheckBox.IsChecked == true && nonCurrentCheckBox.IsChecked == false)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.CurrentStatus == 1));
        }
        else if (nonCurrentCheckBox.IsChecked == true && currentCheckBox.IsChecked == false)
        {
            criteria.Add(new Predicate<CompanyModel>(x => x.CurrentStatus == 0));
        }
        else if (nonCurrentCheckBox.IsChecked == true && currentCheckBox.IsChecked == true)
        {
            criteria.Add(new Predicate<CompanyModel>(x => (x.CurrentStatus == 1 || x.CurrentStatus == 0)));
        }
        //.... All other criterias here
    
        CompanyModel company = o as CompanyModel;
        bool isIn = true;
        if (criteria.Count() == 0)
            return isIn;
        isIn = criteria.TrueForAll(x => x(company));
        return isIn;
    }
    
    private bool FilterCompany(object o){
        return filterCompanyType(o) && filterCompanyInfos(o)
    }
    
    
    public void ApplyFilter(CollectionView companyCollectionView){
        CompanyICollectionView.Filter = this.FilterCompany;
        //do some other stuff like selected index ...
    }
    

    【讨论】:

    • 感谢您的回答。我对FilterCompanyInfos 有点不确定。这是否与我的用户可以搜索名称、城镇、代码等的方法相同?还是该部分也需要在FilterCompanyType 内?
    • filterCompanyInfos 方法是关于按名称/城镇/邮政编码过滤的。您需要对其进行调整,以便在尊重过滤器时此函数为对象返回 true
    • 如何比较一个对象以确保它与已选择的过滤器匹配?
    猜你喜欢
    • 2011-01-09
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 2019-07-12
    相关资源
    最近更新 更多