在DataGridViewCell上绘制ComboBox DropDown箭头

时间:2017-07-14 03:15:28

标签: c# datagridview custom-controls

我想要的是当鼠标在DataGridViewCell上移动时,我想识别鼠标下的单元格,并在其上绘制一个ComboBox DownArrow。当鼠标离开单元格时,我只想绘制“普通”单元格。

我认为我需要在鼠标下绘制单元格,重新绘制之前所在的单元格,以清除以前自定义绘制的箭头。

我这样做的方式如下注意:所有这些代码都在DataGridView级别,而不是单元格级别。

private DataGridViewCell LastCell;
private DataGridViewCell MouseCell;
protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);

    DataGridViewCell currentCell = GetCellUnderCursor();
    if (currentCell != MouseCell)   //Has moved to a new cell
    {
        LastCell = MouseCell;
        MouseCell = currentCell;
        if (currentCell != null) this.InvalidateCell(currentCell);
        if (LastCell != null) this.InvalidateCell(LastCell);
    }
    else
    {
        //Has not changed cell - don't paint again - exit to prevent flicker
        return;
    }
}

我已对此进行了测试,它可以很好地用鼠标在其下面绘制细胞,然后清除其他细胞。

使用此代码完成“测试”,只需在单元格周围绘制一个矩形。

protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
    //call base method
    base.OnCellPainting(e);
    e.PaintContent(e.ClipBounds);
    if (e.RowIndex == -1 || e.ColumnIndex == -1) return;

    //Is the mouse over this cell?
    DataGridViewCell cell = GetCellUnderCursor();
    if (cell == null) return; //row or column is -1

    DataGridViewCell paintingCell = this.Rows[e.RowIndex].Cells[e.ColumnIndex];
    if (paintingCell != cell) return;


    //Paint the cell, excluding the border.
    e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

    //Now paint a custom border.
    using (Pen p = new Pen(Color.RoyalBlue, 1))
    {
        Rectangle rect = e.CellBounds;
        rect.Width -= 2;
        rect.Height -= 2;
        e.Graphics.DrawRectangle(p, rect);
    }
    e.PaintContent(e.ClipBounds);
    e.Handled = true;
}

如上所述,这一切都运行良好 - 我的鼠标围绕DataGridView获得一个漂亮的蓝色矩形。

然后我尝试开发类似的代码来绘制ComboBox Dropdown箭头,并尝试使用ComboBoxRenderer类:

Size arrowSize = new Size(18,20);
Rectangle arrowRectangle = new Rectangle(e.ClipBounds.X + e.ClipBounds.Width - arrowSize.Width -1, e.ClipBounds.Y+1,arrowSize.Width, arrowSize.Height);
Rectangle topTextBoxRectangle = new Rectangle(e.ClipBounds.X, e.ClipBounds.Y, e.ClipBounds.Width, arrowSize.Height+2);
ComboBoxState arrowState = ComboBoxState.Normal;
if (!ComboBoxRenderer.IsSupported)
{
    Debug.WriteLine("Renderer not supported");
    return;
}
else
{
    string cellText = cell.Value == null ? "" : cell.Value.ToString();
    ComboBoxRenderer.DrawDropDownButton(e.Graphics, arrowRectangle, arrowState);
    //ComboBoxRenderer.DrawTextBox(e.Graphics, topTextBoxRectangle, cellText, this.Font, ComboBoxState.Normal);
    e.PaintContent(e.ClipBounds);
}
e.Handled = true;

这根本不适用 - 绘制细胞有时绘制下拉列表(似乎在错误的单元格上绘制它 - 上面的单元格?)如果你正在向下移动鼠标DataGridView,它绘制上面的单元格。如果你正在向上移动它,它会绘制正确的单元格(真的!),向下移动不会清除任何旧图形,但向上移动会有所不同。同样,从左到右移动鼠标会产生正确的行为,但不能从右到左。

我发现e.PaintContents(e.ClipBounds)似乎比ComboBoxRenderer.DrawTextBox()

效果更好

请注意,此代码用于上述代码的“绘制单元格”部分。

有任何建议可以解决这个问题,或者可能出现什么问题?

1 个答案:

答案 0 :(得分:0)

好的 - 问题解决了!

我将绘图设置为:

Rectangle arrowRectangle = new Rectangle(e.ClipBounds.X + e.ClipBounds.Width - arrowSize.Width -1, 
    e.ClipBounds.Y+1,arrowSize.Width, arrowSize.Height);

什么时候应该使用CellBounds,而不是ClipBounds:

Rectangle arrowRectangle = new Rectangle(e.CellBounds.X + e.CellBounds.Width - arrowSize.Width - 1, 
    e.CellBounds.Y + 1, arrowSize.Width, arrowSize.Height);