简体   繁体   中英

LINQ: dynamic Where clause with toggle the combination of cases

I have a list binded to angridview and i want to be able to create filter Where clause 'on the fly', while the combination of filter option controlled by user.

What is the best way to filter the original list by model boolean property and allow to toggle every condition of filter?

I know that the filterdList is not nececery, but every other solution i've already saw doesn't allow toggle the condition of Where clause.

public partial class Form1 : Form
{
    List<dummy> Origlist = new List<dummy> {
        new dummy { pk = 1 ,  istype1 = true,  istype2  = false, istype3=false, istype4=false },
        new dummy { pk = 2 ,  istype1 = true,  istype2 = false,  istype3=false, istype4=false },
        new dummy { pk = 3 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 4 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 5 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 6 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 7 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true },
        new dummy { pk = 8 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true },
        new dummy { pk = 9 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 10 , istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 11 , istype1 = false, istype2 = false,  istype3=false, istype4=false }
        };
    List<dummy> filteredList = new List<dummy>(); 
    public Form1()
    {
        InitializeComponent();
    }

    private void Bind()
    {
        dataGridView1.DataSource = null;
        dataGridView1.DataSource = filteredList;
    }


    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox1.Checked)
        {
            filteredList.AddRange(Origlist.Where(a => a.istype1 == true).ToList());
        }
        else
        {
            filteredList.RemoveAll(a => a.istype1 == true);
        }
        Bind();
    }



    private void checkBox2_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox2.Checked)
        {
            filteredList.AddRange(Origlist.Where(a => a.istype2 == true).ToList());
        }
        else
        {
            filteredList.RemoveAll(a => a.istype2 == true);
        }
        Bind();
    }

    private void checkBox3_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox3.Checked)
        {
            filteredList.AddRange(Origlist.Where(a => a.istype3 == true).ToList());
        }
        else
        {
            filteredList.RemoveAll(a => a.istype3 == true);
        }
        Bind();
    }

    private void checkBox4_CheckedChanged(object sender, EventArgs e)
    {
        if (checkBox4.Checked)
        {
            filteredList.AddRange(Origlist.Where(a => a.istype4 == true).ToList());
        }
        else
        {
            filteredList.RemoveAll(a => a.istype4 == true);
        }
        Bind();
    }

}

模拟

Try something like this (untested):

public partial class Form1 : Form
{
    List<dummy> Origlist = new List<dummy> {
        new dummy { pk = 1 ,  istype1 = true,  istype2  = false, istype3=false, istype4=false },
        new dummy { pk = 2 ,  istype1 = true,  istype2 = false,  istype3=false, istype4=false },
        new dummy { pk = 3 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 4 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 5 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 6 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 7 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true },
        new dummy { pk = 8 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true },
        new dummy { pk = 9 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
        new dummy { pk = 10 , istype1 = false, istype2 = true,   istype3=false, istype4=false },
        new dummy { pk = 11 , istype1 = false, istype2 = false,  istype3=false, istype4=false }
    };

    Options options = new Options();

    private class Options {
        public bool istype1 { get; set; }
        public bool istype2 { get; set; }
        public bool istype3 { get; set; }
        public bool istype4 { get; set; }
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void Bind()
    {
        dataGridView1.DataSource = null;
        dataGridView1.DataSource = OrigList.Where(a =>
          (options.istype1 && a.istype1) ||
          (options.istype2 && a.istype2) ||
          (options.istype3 && a.istype3) ||
          (options.istype4 && a.istype4)
        ).ToList();
    }


    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        options.istype1 = checkBox1.checked;
        Bind();
    }



    private void checkBox2_CheckedChanged(object sender, EventArgs e)
    {
        options.istype2 = checkBox2.checked;
        Bind();
    }

    private void checkBox3_CheckedChanged(object sender, EventArgs e)
    {
        options.istype3 = checkBox3.checked;
        Bind();
    }

    private void checkBox4_CheckedChanged(object sender, EventArgs e)
    {
        options.istype4 = checkBox4.checked;
        Bind();
    }

}

There are other ways you could reduce duplication, but this is a start.

I would say that the easiest/cleanest way is using ADO.NET DataSet for handling your data instead of a using a bunch of List with some Linq query. ADO.NET DataSet is the Official Winforms Way of life .

You could use these dataset/datatable with a BindingSource component as the DataSource of your DataGridView and use the Filter String Property of the BindingSource. This String expression could be easily build by some If clauses testing the state of your CheckBox and String concatenation following the MSND DataColumn Expression syntax.

There are some other clean way like extending the BindingList class with a partial implementation of the IBindingListView interface. But that's some pretty hard stuff, specially when you know that Microsoft has done this work for you for the DataSet... This article is a good place to start if you are not afraid.

a single event handler can be reused for every CheckBox, and that event handler can compare every property with respective CheckBox.

List<dummy> Origlist = new List<dummy> 
{
    new dummy { pk = 1 ,  istype1 = true,  istype2 = false,  istype3=false, istype4=false },
    new dummy { pk = 2 ,  istype1 = true,  istype2 = false,  istype3=false, istype4=false },
    new dummy { pk = 3 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
    new dummy { pk = 4 ,  istype1 = false, istype2 = true,   istype3=false, istype4=false },
    new dummy { pk = 5 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
    new dummy { pk = 6 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
    new dummy { pk = 7 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true  },
    new dummy { pk = 8 ,  istype1 = false, istype2 = false,  istype3=false, istype4=true  },
    new dummy { pk = 9 ,  istype1 = false, istype2 = false,  istype3=true,  istype4=false },
    new dummy { pk = 10 , istype1 = false, istype2 = true,   istype3=false, istype4=false },
    new dummy { pk = 11 , istype1 = false, istype2 = false,  istype3=false, istype4=false }
};

public Form1()
{
    InitializeComponent();
}

private void checkBox_CheckedChanged(object sender, EventArgs e)
{
     dataGridView1.DataSource = Origlist.Where(a => 
         a.istype1 == checkBox1.Checked && 
         a.istype2 == checkBox2.Checked && 
         a.istype3 == checkBox3.Checked && 
         a.istype4 == checkBox4.Checked).ToList();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM