CBreeze
CBreeze

Reputation: 2965

Filtering an ICollectionView on Multiple CheckBoxes

I currently have a list of 27,000 Companies that all fit into at least 1 of 3 categories, Subcontractors, Suppliers and Planthire. All of these companies are loaded into an ICollectionView, which is the ItemsSource for a DataGrid.

what I've previously been able to do in the past is filter the ICollectionView based on one property of a Model. For example if I had a list of jobs, and all jobs had an ITName property attached, I could do something like this;

private void OnCheckBoxCheck(object sender, RoutedEventArgs e)
{
    var checkedEmployees = new HashSet<string>();
    foreach (CheckBox checkBox in _employees.Children)
    {
        if (checkBox.IsChecked == true)
        {
            checkedEmployees.Add((string)checkBox.Content);
            checkedEmployees.Add((string)checkBox.Tag);
        }
    }

    JobsCollectionView.Filter =
        job => checkedEmployees.Contains((job as JobModel).ITName);        
}

The Problem Now

The problem now is that I am trying to filter on multiple properties of a CompanyModel. With irrelevant parts taken out of it it looks like this;

public class CompanyModel
{
    public int Subcontractor { get; set; }
    public int Supplier { get; set; }
    public int Planthire { get; set; }
}

What I would like to do is if the Subcontractor CheckBox is checked but the others aren't, only show Subcontractors. If the Subcontractor and Supplier CheckBoxes are both checked, show Companies that fit into the Subcontractor AND Supplier categories. This is what I have attempted so far, however it does not achieve this;

private void FilterCompanyType(object sender, RoutedEventArgs e)
{
    var checkedCompanyFilters = new HashSet<string>();
    foreach (CheckBox checkBox in companyTypes.Children)
    {
        if (checkBox.IsChecked == true)
        {
            checkedCompanyFilters.Add((string)checkBox.Tag);
        }
    }

    if (subbieCheckBox.IsChecked == true)
    {
        CompanyICollectionView.Filter =
            company => checkedCompanyFilters.Contains((company as CompanyModel).Subcontractor.ToString());
    }

    if (supplierCheckBox.IsChecked == true)
    {
        CompanyICollectionView.Filter =
                company => checkedCompanyFilters.Contains((company as CompanyModel).Supplier.ToString());
    }

    if (planthireCheckBox.IsChecked == true)
    {
        CompanyICollectionView.Filter =
            company => checkedCompanyFilters.Contains((company as CompanyModel).Planthire.ToString());
    }          
}

How can I modify this method so that it achieves what I would like it to?

Upvotes: 2

Views: 343

Answers (2)

Sinatr
Sinatr

Reputation: 21979

You can combine multiple filter conditions:

var isSubbie = subbieCheckBox.IsChecked == true;
var isSupplier = supplierCheckBox.IsChecked == true;
...

CompanyICollectionView.Filter = company =>
{
    var model = (CompanyModel)company;
    return isSubbie && checkedCompanyFilters.Contains(model.Subcontractor.ToString()) ||
        isSupplier && checkedCompanyFilters.Contains(model.Supplier.ToString()) ||
        ...
};

I thought what checkedCompanyFilters is a set of different subcontractors but it looks like you want to filter by just one. Then simply change above return line to something like this (I am not sure how do you define company is subcontractor, is it when Subcontractor > 0 ?):

    return isSubbie && model.Subcontractor > 0 ||
        isSupplier && model.Supplier > 0 ||
        ...

I would still like Subcontractors that are also Suppliers, i.e. model.Subcontractor > 0 && model.Suppliers > 0 if isSubbie && isSupplier

Then simply replace return with either:

    return (isSubbie ? model.Subcontractor > 0 : model.Subcontractor == 0) &&
        (isSupplier ? model.Supplier > 0 : model.Supplier == 0) &&
        ...

or:

    return (isSubbie && model.Subcontractor > 0 || !isSubbie && model.Subcontractor == 0) &&
        (isSupplier && model.Supplier > 0 || !isSupplier && model.Supplier == 0) &&
        ...

Upvotes: 1

The Sharp Ninja
The Sharp Ninja

Reputation: 1041

Your company model should be changed to use an enum for the type of company and a single int for the key. The enum should be declared with the [Flags] attribute so that it can be used for Boolean operations. Then your filters look like this:

CompanyICollectionView.Filter =
    company => checkedCompanyFilters.Where(
        ((company as CompanyModel).CompanyType & CompanyTypes.Whatever) 
            == CompanyTypes.Whatever).Key.ToString();

Upvotes: 1

Related Questions