3

I currently have a DataGrid filled with companies that I am filtering based on two things - one is a search box that the user can filter based on the Company's Name, Town or Postcode. This looks like this;

Filter by Name/Town/Postcode

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

The second method for filtering is based on the Company's type. This is done by the selection of a number of CheckBoxes. This method looks like this;

Filter by Company Type

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

Both of these filtering methods look fine on their own. The issue comes when I want to filter a filter that has already been applied to the DataGrid. For example, the user wants to filter down the company type, so they select the currentCheckBox, the supplierCheckBox and the subbieCheckBox. This returns all current suppliers that are also subcontractors.

This still returns a list of 5000 companies, so the user then wants to use the search functionality to find the company they know the name of. But it doesn't search the filtered CompanyICollection, it resets it and filters the entire list (27000 companies).

I believe that the problem is that I'm creating a new CompanyICollectionView.Fiilter every time, when I want to search an existing one. Is there a way to filter an already filtered ICollectionView?

EDIT (Added dynamic_Filter):

        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;
        }
CBreeze
  • 2,925
  • 4
  • 38
  • 93

2 Answers2

2

You are right, the problem is that you are resetting the filter every time. So you will need to make some modificatons to resolve you problem (I will assume all the code is in the same class):

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 ...
}
ZwoRmi
  • 1,093
  • 11
  • 30
  • Thanks for the answer. I'm a little bit unsure about `FilterCompanyInfos`. Is this just the same as my method where the user can search the name, town, code etc? Or does that part need to also be inside `FilterCompanyType`? – CBreeze Jan 04 '16 at 10:56
  • The filterCompanyInfos method is about Filter by Name/Town/Postcode. You need to adapt it so this function return true for an object when the filter is respected – ZwoRmi Jan 04 '16 at 11:43
  • How can I compare an object to make sure it matches the filters that have been selected? – CBreeze Jan 04 '16 at 15:52
1

There is not need to recreate the filter every time a property changes. What is best for you to do is to combine both filters in one function, pass this to the CompanyICollectionView.Filter and from the property change events to call the CompanyICollectionView.Refresh();. You can even bind you collectionview to an ObservableCollection that supports filtering i.e. FilteredObservableCollection... have a look at: CollectionViewSource Filter not refreshed when Source is changed

Community
  • 1
  • 1