【问题标题】:Need advice about filtering DataGrid需要有关过滤 DataGrid 的建议
【发布时间】:2011-05-13 17:14:09
【问题描述】:

我正在使用 .NET 3.5、C# 和 WinForms。

我的网格有很多列:SellerName、BuyerName、LoadType、LoadName、DriverName、CarSerialNumber 等。我想过滤 BindingSource。我使用 ComboBoxes 做到了这一点,该组合框在 DropDown 上填充了网格单元格的值,但它不实用并且会导致表单看起来很糟糕。

我需要关于什么是让用户选择网格值然后使用按钮进行过滤的最佳方式的建议。我可以让它像在 Excel 中一样吗?列标题上有一个按钮,当用户按下它时,它会显示一个带有选中列表框的小菜单。当用户检查任何值并按下按钮时,它开始过滤。

请给我一些建议。

这是 Excel 的图片:

谢谢!

【问题讨论】:

    标签: c# datagrid filter


    【解决方案1】:

    嗯,
    首先你应该创建你的自定义过滤器用户控件,就像你希望在 excel 中的一样。

    其次,这并不容易,但您可以将过滤器按钮添加到网格(只需执行 grid.Controls.Add(...)),并通过覆盖 OnColumnWidthChanged/OnColumnHeadersHeightChangedDatagridView 使它们与列标题对齐。

    最后,当用户单击过滤器按钮时,您可以打开一个嵌入了您的自定义过滤器的ToolStripDropDown,我的意思是类似于此答案(显然使用您的控件而不是列表视图):
    @987654321 @


    编辑:

    这是一个(工作的)代码示例:

    自定义列标题单元格类:

    public class DataGridFilterHeader : DataGridViewColumnHeaderCell
    {
        PushButtonState currentState = PushButtonState.Normal;
        Point cellLocation;
        Rectangle buttonRect;
    
        public event EventHandler<ColumnFilterClickedEventArg> FilterButtonClicked;
    
        protected override void Paint(Graphics graphics,
                                      Rectangle clipBounds,
                                      Rectangle cellBounds,
                                      int rowIndex,
                                      DataGridViewElementStates dataGridViewElementState,
                                      object value,
                                      object formattedValue,
                                      string errorText,
                                      DataGridViewCellStyle cellStyle,
                                      DataGridViewAdvancedBorderStyle advancedBorderStyle,
                                      DataGridViewPaintParts paintParts)
        {
            base.Paint(graphics, clipBounds,
                       cellBounds, rowIndex,
                       dataGridViewElementState, value,
                       formattedValue, errorText,
                       cellStyle, advancedBorderStyle, paintParts);
    
            int width = 20; // 20 px
            buttonRect = new Rectangle(cellBounds.X + cellBounds.Width - width, cellBounds.Y, width, cellBounds.Height);
    
            cellLocation = cellBounds.Location;
            // to set image/ or some other properties to the filter button look at DrawButton overloads
            ButtonRenderer.DrawButton(graphics,
                                      buttonRect,
                                      "F",
                                      this.DataGridView.Font,
                                      false,
                                      currentState);
        }
    
        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            if (this.IsMouseOverButton(e.Location))
                currentState = PushButtonState.Pressed;
            base.OnMouseDown(e);
        }
        protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
        {
            if (this.IsMouseOverButton(e.Location))
            {
                currentState = PushButtonState.Normal;
                this.OnFilterButtonClicked();
            }
            base.OnMouseUp(e);
        }
        private bool IsMouseOverButton(Point e)
        {
            Point p = new Point(e.X + cellLocation.X, e.Y + cellLocation.Y);
            if (p.X >= buttonRect.X && p.X <= buttonRect.X + buttonRect.Width &&
                p.Y >= buttonRect.Y && p.Y <= buttonRect.Y + buttonRect.Height)
            {
                return true;
            }
            return false;
        }
        protected virtual void OnFilterButtonClicked()
        {
            if (this.FilterButtonClicked != null)
                this.FilterButtonClicked(this, new ColumnFilterClickedEventArg(this.ColumnIndex, this.buttonRect));
        }
    }
    

    自定义事件参数:

    public class ColumnFilterClickedEventArg : EventArgs
    {
        public int ColumnIndex { get; private set; }
        public Rectangle ButtonRectangle { get; private set; }
        public ColumnFilterClickedEventArg(int colIndex, Rectangle btnRect)
        {
            this.ColumnIndex = colIndex;
            this.ButtonRectangle = btnRect;
        }
    }
    

    DataGridView 覆盖:

    public class DataGridWithFilter : DataGridView
    {
        protected override void OnColumnAdded(DataGridViewColumnEventArgs e)
        {
            var header = new DataGridFilterHeader();
            header.FilterButtonClicked += new EventHandler<ColumnFilterClickedEventArg>(header_FilterButtonClicked);
            e.Column.HeaderCell = header;
            base.OnColumnAdded(e);
        }
    
        void header_FilterButtonClicked(object sender, ColumnFilterClickedEventArg e)
        {
            // open a popup on the bottom-left corner of the
            // filter button
            // here's we add a simple hello world textbox, but you should add your filter control
            TextBox innerCtrl = new TextBox();
            innerCtrl.Text = "Hello World !";
            innerCtrl.Size = new System.Drawing.Size(100, 30);
    
            var popup = new ToolStripDropDown();
            popup.AutoSize = false;
            popup.Margin = Padding.Empty;
            popup.Padding = Padding.Empty;
            ToolStripControlHost host = new ToolStripControlHost(innerCtrl);
            host.Margin = Padding.Empty;
            host.Padding = Padding.Empty;
            host.AutoSize = false;
            host.Size = innerCtrl.Size;
            popup.Size = innerCtrl.Size;
            popup.Items.Add(host);
    
            // show the popup
            popup.Show(this, e.ButtonRectangle.X, e.ButtonRectangle.Bottom);
        }
    }
    

    结果:


    编辑 2:

    这是一个完整的 VS2008 项目示例(带有自定义过滤器的 DataGrid,而不仅仅是“Hello World”):--> http://www.mediafire.com/?s6o8jmpzh0t82v2

    【讨论】:

    • 我无法添加按钮,它位于网格上,只有一个我想位于所有列标题文本的左侧。 datagridview1.Controls.Add(btnFiler);
    • 您(部分)正确,我设法使用自定义 DataGridViewColumnHeaderCell 完成您需要的操作。看看我的编辑,我真的希望这会有所帮助(这有点累)。 ;)
    • 哇。太晚了,我会睡得很开心,明天再做。你是最好的。我很高兴。自“14 小时前回答”以来,我一直在尝试做某事,但什么也没有……非常感谢。
    • 我无法使用此代码 :( 我不知道在哪里插入以及如何调用
    • 只需使用我发布的 3 个类创建 3 个文件。然后使用DataGridWithFilter 而不是通常的DataGridView。项目编译后,您甚至应该在设计器工具箱中看到 DataGridWithFilter 项目,因此您可以根据需要将其拖放到表单上。否则,以编程方式将其添加到您的表单中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 2011-02-21
    相关资源
    最近更新 更多