用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用来显示筛选的语句。

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

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、运行界面

2、点击列标题

3、点击边上的列标题,panel自动调整位置

4、按salary升序排列

5、填写筛选条件

6、填入两个条件

7、查询结果,在下方状态条显示筛选条目

8、多加一些条件

9、最终效果

注:由于toolStripStatusLabel的内容文字一旦超过最大宽度,该控件就会被隐藏,所以我把窗体拉长了点。至于怎么让它部分显示,没有查到。其实下面这个状态条完全可以用panel+label来实现,这样文字一旦超出label范围,就可以部分显示了。

        /*************************************************************
         *
         * 来自于C#初学者——phoenix
         * 2015年5月22日
         * http://blog.csdn.net/phoenix36999
         *
         * **********************************************************/
时间: 2024-10-10 10:39:56

用DataGridView实现Excel列的复杂筛选功能的相关文章

DataGridView如何实现列标头带数据筛选功能,就象Excel高级筛选功能一样

'近日有本论坛网友问:DataGridView如何实现列标头带数据筛选功能,就象Excel高级筛选功能一样 '今晚正好闲着没事,加之以前也没用到过这个需求,所以就写了个模拟功能,供各位坛友酌情参考. 'VB.NET 2008 环境 '新建一个项目后,只需在Form1中拉一个DataGridView,一个ComboBox,然后将下面代码复制粘贴即可,其它什么也不用做 Public Class Form1 Dim SelectedCol As Integer = 0, IsFindit As Boo

NPOI DataGridView导出EXCEL

NPOI 官方网站 http://npoi.codeplex.com/ 加载NPOI.DLL ,引用这两个命名空间 using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; #region NPOI DataGridView 导出 EXCEL /// <summary> /// NPOI DataGridView 导出 EXCEL /// </summary> /// <param name="fileName"

Excel碰到空行无法筛选排序解决方法

Excel碰到空行无法筛选排序解决方法 有时候excel可真心考人智商,一列中有空行,那么你就只能筛选排序首个空行前的内容了,解决方法来了,做个小记录,以防今后忘了. 1.在首列插入一列: 2.全选该列输入1,使用快捷键"Ctrl+回车键"填充整列: 3.选择首行,点击"数据-->筛选-->自动筛选",现在可以全部筛选及排序了 Excel碰到空行无法筛选排序解决方法,布布扣,bubuko.com

Winform将DataGridView导出Excel,调用打印机打印DataGridView

DataGridView导出Excel (这个需要 Microsoft.Office.Interop.Excel.dll  在网上下载就可以) public static void ExportExcel(string fileName, DataGridView myDGV) { string saveFileName = ""; SaveFileDialog saveDialog = new SaveFileDialog(); saveDialog.DefaultExt = &qu

C# WinForm DataGridView 给标题列增加序号及格式化某个字段

DataGridView 给标题列增加序号 private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) { DataGridViewTextBoxColumn dgv_Text = new DataGridViewTextBoxColumn(); for (int i = 0; i < dataGridView1.Rows.Count; i++) { i

pandas的筛选功能,跟excel的筛选功能类似,但是功能更强大。

Select rows from a DataFrame based on values in a column -pandas 筛选 https://stackoverflow.com/questions/17071871/select-rows-from-a-dataframe-based-on-values-in-a-column-in-pandas pandas的筛选功能,跟excel的筛选功能类似,但是功能更强大. 在SQL数据中, 我们可以用这样的语句: select * from

PHP:数字转Excel列头

转自我的个人博客:阔野飞花 http://www.rexcao.net/archives/169 前段时间升级一个项目的Excel导出功能,这次的列数大概有60多条,在处理过程中发现一个问题,原先做好的数字转Excel列头功能现在只到 AZ列就结束了,那显然是不够用啊,后来再仔细查看,发现,原来AZ列之后的内容显示到AAA列上面了,然后看了看原来的代码才发现,原来的逻辑错了! 我原来的错误逻辑是这样的:A-Z,Z下来是AA,AA-AZ,AZ下来是AAA,下来是AAAA依次类推...但是Excel

WinForm设置DataGridView某些行和列只读

WinForm设置DataGridView某些行和列的只读 列只读设置比较容易,行只读设置要求将SelectionMode设置为CellSelect,EditMode设置为EditOnEnter . '--DataGridView1控件的初始化设置(在数据绑定前设置,load事件中) Private Sub InitDataGrid1() Me.GridView1.ReadOnly = False '设置非只读 Me.GridView1.SelectionMode = DataGridViewS

根据Excel列类型获取列的值

using System.Data; using System.IO; using System.Text; using System.Web; using NPOI.SS.UserModel; using NPOI.HSSF.UserModel; namespace AIMSCommon { public class ExcelRender { /// <summary> /// 根据Excel列类型获取列的值 /// </summary> /// <param name=