天天看点

用DataGridView实现Excel列的复杂筛选功能

有个项目,客户要求表格要像Excel那样具有根据列的复杂筛选功能,而且最好不要改变太多原先的使用习惯。

上网搜了一下,大部分的都是把整列绑定到一个combobox上,覆盖到列标题上,从而达到简单的筛选功能。

仔细研究了下Excel的复杂筛选,仅靠DataGridView的右键功能不太好完全实现,于是就想到用一个panel来当筛选面板。

===================================================================

新建一个项目,form1中拖入一个datagridview,一个panel,一个statusStrip。

panel中如图所示放上2个label,7个button,3个combobox,1个listbox。

statusStrip中放入3个toolStripStatusLabel。

点击“升序”或者“降序”可以直接根据这一列来进行排序。

在筛选条件中,第一个combobox来选择“与”或者“或”,第二个combobox用来显示等于、大于、小于、包含等等,第三个combobox用来显示当前列所有非重复内容。

点击“添加条件”可以把上面的筛选条件添加到listbox中,选中listbox中的一个条件,点击“移除条件”可以移除该条件。

最后点击“确定”执行筛选,点击“取消”撤销本次所做的操作。

toolStripStatusLabel1用来显示按某一列升序或者降序排列。

toolStripStatusLabel2用来显示从N条数据中筛选到了M条数据。

toolStripStatusLabel3用来显示筛选的语句。

用DataGridView实现Excel列的复杂筛选功能

--------------------------------------------------

1、定义5个全局变量

DataTable dt;
        DataView dv;
        int row_total;//总行数
        int row_select; //筛选后行数
        string[] str_ltb;//存储筛选条件数组
           
2、给datagridview填入数据并初始化一些数据
private void Form1_Load(object sender, EventArgs e)
        {
            dt = new DataTable();
            dt.Columns.Add("ID", Type.GetType("System.Int32"));
            dt.Columns[0].AutoIncrement = true;  //列值自动递增
            dt.Columns[0].AutoIncrementSeed = 1;  //起始值
            dt.Columns[0].AutoIncrementStep = 1;  //步长

            dt.Columns.Add("Name", Type.GetType("System.String"));
            dt.Columns.Add("Birthday", Type.GetType("System.String"));
            dt.Columns.Add("Address", Type.GetType("System.String"));
            dt.Columns.Add("Salary", Type.GetType("System.Int32"));

            dt.Rows.Add(new object[] { null, "张一", "1980-01-01", "北京", 15000 });
            dt.Rows.Add(new object[] { null, "张二", "1981-02-28", "上海", 20000 });
            dt.Rows.Add(new object[] { null, "张三", "1982-03-18", "北京", 10000 });
            dt.Rows.Add(new object[] { null, "张四", "1983-04-01", "河北", 5000 });
            dt.Rows.Add(new object[] { null, "张五", "1984-05-14", "北京", 8000 });
            dt.Rows.Add(new object[] { null, "李一", "1985-10-01", "广州", 11000 });
            dt.Rows.Add(new object[] { null, "李二", "1986-09-07", "上海", 18000 });
            dt.Rows.Add(new object[] { null, "李三", "1987-06-10", "北京", 20000 });
            dt.Rows.Add(new object[] { null, "李四", "1988-04-01", "广州", 5000 });
            dt.Rows.Add(new object[] { null, "李五", "1989-03-05", "北京", 7000 });
            dt.Rows.Add(new object[] { null, "王一", "1983-01-09", "广州", 15000 });
            dt.Rows.Add(new object[] { null, "王二", "1985-12-03", "上海", 30000 });
            dt.Rows.Add(new object[] { null, "王三", "1987-08-22", "北京", 5000 });
            dt.Rows.Add(new object[] { null, "王四", "1989-01-15", "河北", 3000 });
            dt.Rows.Add(new object[] { null, "王五", "1989-05-20", "北京", 11000 });

            //dgv.DataSource = dt;
            dgv.Dock = DockStyle.Fill;
            row_total = dt.Rows.Count;
            dv = dt.DefaultView;
            dgv.DataSource = dv;
            row_select = row_total;

            //禁止点击列标题自动排序
            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                dgv.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
            }

            pl_dgv_extend.Visible = false;
            toolStripStatusLabel1.Text = "按 ID 列升序排列";
            toolStripStatusLabel2.Text = "在 " + row_total + " 条数据中找到 " + row_select + " 个";
            toolStripStatusLabel3.Text = "";
        }
           
3、点击dgv列标题,panel显示,并根据列标题的不同位置,对应显示到相应的位置
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            int dLeft, dTop;
            //获取dgv列标题位置相对坐标
            Rectangle range = dgv.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
            //计算pl_dgv_extend位置坐标
            dLeft = range.Left + dgv.Left;
            dTop = range.Top + dgv.Top + range.Height;
            //设置pl_dgv_extend位置,超出框体宽度时,和dgv右边对齐
            if (dLeft + pl_dgv_extend.Width > this.Width)
            {
                pl_dgv_extend.SetBounds(dgv.Width - pl_dgv_extend.Width, dTop, pl_dgv_extend.Width, pl_dgv_extend.Height);
            }
            else
            {
                pl_dgv_extend.SetBounds(dLeft, dTop, pl_dgv_extend.Width, pl_dgv_extend.Height);
            }
            //设置cb_condition下拉菜单内容
            cb_condition.Items.Clear();
            for (int i = 0; i < dgv.Rows.Count; i++)
            {
                bool isfind = false;
                for (int j = 0; j < cb_condition.Items.Count; j++)
                {
                    if (cb_condition.Items[j].ToString() == dgv.Rows[i].Cells[e.ColumnIndex].Value.ToString())
                    {
                        isfind = true;
                        j = cb_condition.Items.Count;//break
                    }
                }
                if (!isfind)
                {
                    cb_condition.Items.Add(dgv.Rows[i].Cells[e.ColumnIndex].Value.ToString());
                }
            }

            pl_dgv_extend.Visible = true;
            lb_columnname.Text = dgv.Columns[e.ColumnIndex].Name;
            //初始化选择项
            cb_andor.SelectedIndex = 0;
            cb_operator.SelectedIndex = 0;
            cb_condition.Text = "";
            //存储现有的筛选条件选项
            if (ltb_condition.Items.Count == 0)
            {
                str_ltb = null;
            }
            else
            {
                str_ltb = new string[ltb_condition.Items.Count];
                ltb_condition.Items.CopyTo(str_ltb, 0);
            }
        }
           
4、升序降序代码
private void bt_asc_Click(object sender, EventArgs e)
        {
            dv.Sort = lb_columnname.Text + " asc";

            toolStripStatusLabel1.Text = "按 " + lb_columnname.Text + " 列升序排列";
            pl_dgv_extend.Visible = false;
        }

        private void bt_desc_Click(object sender, EventArgs e)
        {
            dv.Sort = lb_columnname.Text + " desc";

            toolStripStatusLabel1.Text = "按 " + lb_columnname.Text + " 列降序排列";
            pl_dgv_extend.Visible = false;
        }
           
5、添加筛选条件
private void bt_add_Click(object sender, EventArgs e)
        {
            //空值判断
            if (cb_operator.SelectedItem == null || cb_condition.Text.Trim() == "")
            {
                MessageBox.Show("请选择条件!");
                return;
            }
            if (cb_andor.SelectedItem == null && ltb_condition.Items.Count > 0)
            {
                MessageBox.Show("请选择条件!");
                return;
            }
            //文字转运算符
            string str_andor = "", str_operator = "";
            if (ltb_condition.Items.Count > 0)
            {
                if (cb_andor.SelectedItem == null) str_andor = "";
                else if (cb_andor.SelectedItem.ToString() == "或") str_andor = "or ";
                else str_andor = "and ";
            }
            if (cb_operator.SelectedItem.ToString() == "等于") str_operator = "= ";
            else if (cb_operator.SelectedItem.ToString() == "大于") str_operator = "> ";
            else if (cb_operator.SelectedItem.ToString() == "大于等于") str_operator = ">= ";
            else if (cb_operator.SelectedItem.ToString() == "小于") str_operator = "< ";
            else if (cb_operator.SelectedItem.ToString() == "小于等于") str_operator = "<= ";
            else str_operator = "like ";
            //筛选条件添加到listbox
            if (cb_operator.SelectedItem.ToString() == "包含")
            {
                ltb_condition.Items.Add(str_andor + lb_columnname.Text + " " + str_operator + "'*" + cb_condition.Text.Trim() + "*'");
            }
            else
            {
                ltb_condition.Items.Add(str_andor + lb_columnname.Text + " " + str_operator + "'" + cb_condition.Text.Trim() + "'");
            }
            //初始化筛选条件
            cb_andor.SelectedIndex = 0;
            cb_operator.SelectedIndex = 0;
            cb_condition.Text = "";
        }
           
6、移除筛选条件
private void bt_remove_Click(object sender, EventArgs e)
        {
            if (ltb_condition.SelectedItem == null)
            {
                MessageBox.Show("请选择需要移除的项!");
                return;
            }
            int rownum = ltb_condition.SelectedIndex;
            ltb_condition.Items.RemoveAt(rownum);
            //如果移除了第一项并且移除后listbox项数目大于0
            //把第一项开头的and或者or去掉
            if (ltb_condition.Items.Count > 0 && rownum == 0)
            {
                string first = ltb_condition.Items[0].ToString();
                string result;
                if (first.Substring(0, 2) == "or")
                {
                    result = first.Substring(2, first.Length - 3);
                }
                else
                {
                    result = first.Substring(3, first.Length - 4);
                }
                ltb_condition.Items.RemoveAt(0);
                ltb_condition.Items.Insert(0, result);
            }
        }
           
7、清除所有筛选条件
private void bt_clear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("是否要移除所有筛选条件?", "警告", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                ltb_condition.Items.Clear();
            }
            dv.RowFilter = ""; //清空筛选条件
            pl_dgv_extend.Visible = false;
            row_select = row_total;
            toolStripStatusLabel2.Text = "在 " + row_total + " 条数据中找到 " + row_select + " 个";
            toolStripStatusLabel3.Text = "";
        }
           
8、确认,执行筛选程序
private void bt_ok_Click(object sender, EventArgs e)
        {
            if (ltb_condition.Items.Count == 0)
            {
                dv.RowFilter = "";
                toolStripStatusLabel3.Text = "";
            }
            else
            {
                for (int i = 0; i < ltb_condition.Items.Count; i++)
                {
                    if (i == 0) toolStripStatusLabel3.Text = ltb_condition.Items[0].ToString();
                    else toolStripStatusLabel3.Text += " " + ltb_condition.Items[i].ToString();
                }
                dv.RowFilter = toolStripStatusLabel3.Text;
            }
            pl_dgv_extend.Visible = false;
            row_select = dv.Count;
            toolStripStatusLabel2.Text = "在 " + row_total + " 条数据中找到 " + row_select + " 个";
        }
           
9、取消,回滚操作
private void bt_cancle_Click(object sender, EventArgs e)
        {//回滚操作
            ltb_condition.Items.Clear();
            if (str_ltb != null) ltb_condition.Items.AddRange(str_ltb);
            pl_dgv_extend.Visible = false;
        }
           

--------------------------------------------------

以上就是所有的代码了,新手,大家就将就着看吧。下面来看一下实际运行效果。

=========================================================

1、运行界面

用DataGridView实现Excel列的复杂筛选功能
2、点击列标题
用DataGridView实现Excel列的复杂筛选功能
3、点击边上的列标题,panel自动调整位置
用DataGridView实现Excel列的复杂筛选功能
4、按salary升序排列
用DataGridView实现Excel列的复杂筛选功能
5、填写筛选条件
用DataGridView实现Excel列的复杂筛选功能
6、填入两个条件
用DataGridView实现Excel列的复杂筛选功能
7、查询结果,在下方状态条显示筛选条目
用DataGridView实现Excel列的复杂筛选功能
8、多加一些条件
用DataGridView实现Excel列的复杂筛选功能
9、最终效果
用DataGridView实现Excel列的复杂筛选功能
注:由于toolStripStatusLabel的内容文字一旦超过最大宽度,该控件就会被隐藏,所以我把窗体拉长了点。至于怎么让它部分显示,没有查到。其实下面这个状态条完全可以用panel+label来实现,这样文字一旦超出label范围,就可以部分显示了。
/*************************************************************
         * 
         * 来自于C#初学者——phoenix
         * 2015年5月22日
         * http://blog.csdn.net/phoenix36999
         * 
         * **********************************************************/