如何用自定义标题替换 DataGridView 的 HeaderCells?

Posted

技术标签:

【中文标题】如何用自定义标题替换 DataGridView 的 HeaderCells?【英文标题】:How to replace the HeaderCells of a DataGridView with custom headers? 【发布时间】:2020-07-21 05:31:42 【问题描述】:

当 DataGridView 的 DataSource 已设置为 DataTable 对象并保留前一个 HeaderCell 的文本时,何时将 DataGridViewColumnHeaderCell 替换为自定义 HeaderCell(此处为:CustomDataGridViewColumnHeaderCell) ,设置为DataTable对应Column的名称?

我有一个DataGridView 的自定义标头类:

public class CustomDataGridViewColumnHeaderCell : DataGridViewColumnHeaderCell

    // adds a button to the header

DataTable 被设置为DataSource,自动创建列。如何用自定义标题单元格替换默认标题单元格(上述实例)?

更多细节

要解决的问题是,DataGridView 需要在其标题单元格中嵌入可点击按钮,箭头在上面的屏幕截图中指向。为此,有一个类CustomDataGridViewColumnHeaderCell。为了在DataGridView 中显示数据,DataTable 被指定为其数据源。例如:

myDataGridView.DataSource = myDataTable;

完成此操作后,DataGridView 的列将与DataTable 中的列相对应。我从默认标题类派生了一个类,以便按钮出现在列标题内。

【问题讨论】:

您能详细说明一下吗。到底是在做什么。 @BheemsenSingh 我会在帖子中添加更多细节。 @MongZhu 我想你误会了。简而言之,当我分配DataTable 时,我希望列标题类型为CustomDataGridViewColumnHeaderCell : DataGridViewColumnHeaderCell,而不是默认的DataGridViewColumnHeaderCell,但标题名称仍与DataTable 相对应。 您是否尝试过遍历列集合并将其替换为自定义列? 其实有一个点击事件可以用来处理这个工作。 【参考方案1】:

DataGridViewColumn 的HeaderCell 可以随时替换。

即使已经设置了 DataGridView 的数据源:在这种情况下,您可能希望将当前 HeaderCell 的样式设置为新单元格,以防需要复制某些值(当列是自动-生成,可能没有太多要复制的,但是既然可以设置Style属性,那就设置吧)。

在示例中,我向自定义 HeaderCell 添加了一个 ReplaceHeaderCell() 方法,该方法接收当前标头的实例,复制一些属性,然后在替换相应的之前处理它列的HeaderCell 本身。

如果我们添加到HeaderCell 的按钮是标准按钮控件,则必须将此控件添加到DataGridView.Controls 集合中(这样它才会可见并放在前面)。 如果 Button 被绘制,覆盖Paint method,当然没有任何父项:)。

注意: Button 是在 OnDataGridViewChanged() 方法覆盖中添加的。每次 DataGridView 对象成为 HeaderCell 的所有者时都会调用此方法。当 Parent DataGridView 发生变化时,Button 会自动添加到其 Controls 集合中。

► 在这里,Paint 方法无论如何都会被覆盖:它用于计算 HeaderCell 文本填充,因此 Button 不会重叠并隐藏 Column 的文本(此过程需要根据 Button 的细节进行微调)。

要替换列的当前HeaderCell(例如Column[0]),只需创建自定义HeaderCell 的新实例并调用ReplaceHeaderCell() 方法,传递HeaderCell 的引用来替换:

var newButtonHeaderCell = new DGVButtonHeaderCell();
newButtonHeaderCell.ReplaceHeaderCell(dataGridView1.Columns[0].HeaderCell);

这就是它的工作原理:

using System.Drawing;
using System.Windows.Forms;

class DGVButtonHeaderCell : DataGridViewColumnHeaderCell

    public readonly Button button;
    private Padding m_ButtonPadding = Padding.Empty;

    public DGVButtonHeaderCell(int buttonWidth = 40)
    
        button = new Button()  BackColor = Color.Orange, Width = buttonWidth ;
        m_ButtonPadding = new Padding(button.Width + 2, 0, 0, 0);
        button.Click += ButtonClick;
    

    public void ReplaceHeaderCell(DataGridViewColumnHeaderCell previousHeader)
    
        if (previousHeader == null) return;
        SetStandardValues(previousHeader);
        var dgv = previousHeader.DataGridView;
        dgv.Columns[previousHeader.OwningColumn.Index].HeaderCell = this;
        previousHeader.Dispose();
    

    private void SetStandardValues(DataGridViewColumnHeaderCell previous)
    
        if (previous == null) return;
        this.Style = previous.Style;
        button.Font = this.Style.Font ?? previous.DataGridView.ColumnHeadersDefaultCellStyle.Font;
        // etc.
    

    private void ButtonClick(object sender, EventArgs e)
    
        OnClick(new DataGridViewCellEventArgs(ColumnIndex, RowIndex));
        MessageBox.Show("You clicked me");
    

    protected override void OnDataGridViewChanged()
    
        if (this.DataGridView == null) return;
        this.DataGridView.Controls.Add(button);
    

    protected override void Paint(Graphics g, Rectangle clipBounds, Rectangle bounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advBorderStyle, DataGridViewPaintParts parts)
    
        cellStyle.Padding = Padding.Add(m_ButtonPadding, cellStyle.Padding);
        base.Paint(g, clipBounds, bounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advBorderStyle, parts);
        button.Location = new Point(bounds.Left, bounds.Top + 2);
        button.Height = bounds.Height - 4;
    

    protected override void Dispose(bool disposing)
    
        if (disposing) 
            button.MouseClick -= ButtonClick;
            button.Dispose();
        
        base.Dispose(disposing);
    

【讨论】:

以上是关于如何用自定义标题替换 DataGridView 的 HeaderCells?的主要内容,如果未能解决你的问题,请参考以下文章

Cordova android - 如何用生成的替换自定义 build.gradle

如何用不同的 Xib 替换我的自定义视图

如何用自定义字符串完全替换 pytest 输出以进行测试?

如何用自定义 <comment> 元素替换 HTML 注释

如何用自定义变量替换 DJANGO 中 JAVASCRIPT 脚本生成的 Google Map Key

如何用自定义alterna替换管理标题中的默认WordPress-W-logo