【问题标题】:Problem while scrolling merged Header Cells of a DataGridView滚动 DataGridView 的合并标题单元格时出现问题
【发布时间】:2021-07-18 02:54:52
【问题描述】:

在我的 WinForm 项目中,我有一个 DataGridView 控件。
我实现了合并 2 列的标题单元格。它工作正常,但滚动时出现问题。下面的图片应该可以解释它。
有人可以帮忙吗?

这是我用来合并列标题单元格的代码。
合并列的索引为2021

private void loadEvents()
{
    this.dgv_db_door.Paint += new PaintEventHandler(dgv_db_door_Paint);
    this.dgv_db_door.Scroll += new ScrollEventHandler(dgv_db_door_Scroll);
    this.dgv_db_door.ColumnWidthChanged += DataGridView1_ColumnWidthChanged;
    this.dgv_db_door.Resize += DataGridView1_Resize;
}

private void dgv_db_door_Paint(object sender, PaintEventArgs e)
{
     string doorCloser = "DOOR CLOSER";
    
     //Index numbers of merged columns ara 20 and 21;
     int mergedColumn1 = 20;
     int mergedColumn2 = 21;
     Rectangle r1 = dgv_db_door.GetCellDisplayRectangle(mergedColumn1, -1, true);
     int w2 = dgv_db_door.GetCellDisplayRectangle(mergedColumn2, -1, true).Width;
     r1.X += 1;
     r1.Y += 1;
     r1.Width = r1.Width + w2 - 2;
     r1.Height = r1.Height / 2 - 2;
     e.Graphics.FillRectangle(new SolidBrush(dgv_db_door.ColumnHeadersDefaultCellStyle.BackColor), r1);
    
    StringFormat format = new StringFormat();
    
    format.Alignment = StringAlignment.Center;
    format.LineAlignment = StringAlignment.Center;
    e.Graphics.DrawString(doorCloser, dgv_db_door.ColumnHeadersDefaultCellStyle.Font,
    new SolidBrush(dgv_db_door.ColumnHeadersDefaultCellStyle.ForeColor), r1, format);
                 
}
private void dgv_db_door_Scroll(object sender, ScrollEventArgs e)
{
    if (e.OldValue > e.NewValue)
    {
                
    }
    else
    {
        this.InvalidateHeader();
    }
}

private void DataGridView1_Resize(object sender, EventArgs e)
{
    this.InvalidateHeader();
}
    
private void DataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
     this.InvalidateHeader();
}

private void InvalidateHeader()
{
     Rectangle rtHeader = this.dgv_db_door.DisplayRectangle;
     rtHeader.Height = this.dgv_db_door.ColumnHeadersHeight / 2;
    this.dgv_db_door.Invalidate(rtHeader);
}

【问题讨论】:

    标签: c# winforms merge datagridview graphics


    【解决方案1】:

    对绘图过程的一些修改:

    注意 1:我在 DataGridView 中添加了双缓冲,以避免在单击标题单元格时出现任何闪烁。当网格需要渲染大量行时,它可能会产生影响。

    注意 2:您可以删除所有这些 InvalidateHeader() 调用,此处不需要。

    ► 此新行为允许随时重置包含在自定义标题和标题文本中的列范围(如视觉示例所示)。


    这就是现在的样子:


    using System.Reflection;
    
    TextFormatFlags centerTopflags = 
        TextFormatFlags.HorizontalCenter | TextFormatFlags.Top | TextFormatFlags.PreserveGraphicsClipping;
    string mergedHeaderText = string.Empty;
    int[] mergedColumns = null; 
    
    public void SomeForm()
    {
        this.InitializeComponent();
        var flags = BindingFlags.Instance | BindingFlags.NonPublic;
        dgvTest.GetType().GetProperty("DoubleBuffered", flags).SetValue(dgvTest, true);
        mergedColumns = new int[] { 20, 21 };
        mergedHeaderText = "DOOR CLOSER"
    }
    
    private void dgv_db_door_Paint(object sender, PaintEventArgs e)
    {
        var dgv = sender as DataGridView;
        var headerStyle = dgv.ColumnHeadersDefaultCellStyle;
        int colsWidth = -1;
        int colsLeft = 1;
    
        // Absolute Width of the merged Column range
        for (int i = 0; i < mergedColumns.Length; i++) {
            var col = dgv.Columns[mergedColumns[i]];
            colsWidth += col.Visible ? col.Width : 0;
        }
    
        // Absolute Left position of the first Column to merge
        if (mergedColumns[0] > 0) {
            colsLeft += dgv.Columns.OfType<DataGridViewColumn>()
                .Where(c => c.Visible).Take(mergedColumns[0]).Sum(c => c.Width);
        }
    
        // Merged Headers raw drawing  Rectangle
        var r = new Rectangle(
            dgv.RowHeadersWidth + colsLeft - dgv.HorizontalScrollingOffset, 2, 
            colsWidth, dgv.ColumnHeadersHeight);
    
        // Measure the Height of the text to render - no wrapping
        r.Height = TextRenderer.MeasureText(e.Graphics, mergedHeaderText, headerStyle.Font, r.Size, centerTopflags).Height;
    
        // Draw the merged Headers only if visible on screen
        if (r.Right > dgv.RowHeadersWidth || r.X < dgv.DisplayRectangle.Right) {
            // Clip the drawing Region to exclude the Row Header
            var clipRect = new Rectangle(
                dgv.RowHeadersWidth + 1, 0, 
                dgv.DisplayRectangle.Width - dgv.RowHeadersWidth, dgv.ColumnHeadersHeight);
            e.Graphics.SetClip(clipRect);
    
            using (var brush = new SolidBrush(headerStyle.BackColor)) e.Graphics.FillRectangle(brush, r);
            TextRenderer.DrawText(e.Graphics, mergedHeaderText, headerStyle.Font, r, headerStyle.ForeColor, centerTopflags);
            e.Graphics.ResetClip();
        }
    }
    

    【讨论】:

    • 感谢有用的信息。你帮助我理解了工作的逻辑。您对边境情况的看法是正确的。我用你的代码改变了我的代码。但是还是有问题。如果你有兴趣,我想分享。 link
    • 现在完美了!再次感谢:)。
    猜你喜欢
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 2011-05-19
    • 2018-06-05
    • 2011-10-30
    • 1970-01-01
    相关资源
    最近更新 更多