简体   繁体   English

如何在 WinForms DataGrid 中绘制所选行的边框?

[英]How to paint the border of the selected Row in a WinForms DataGrid?

在此处输入图像描述 I have an custom control derived from the old WinForms DataGrid .我有一个从旧的WinForms DataGrid派生的自定义控件。
I want to draw a border around the selected row when a User clicks it: the Row border, not a Cell's border, or change the Row's background color, etc.当用户单击它时,我想在所选行周围绘制一个边框:行边框,而不是单元格的边框,或者更改行的背景颜色等。

在此处输入图像描述

Like the row in the graphics example (a red line on the 3rd row of the DataGrid).就像图形示例中的行(DataGrid 的第 3 行上的红线)。
I don't want it to be like the first row, with a blue background.我不希望它像第一行一样,有蓝色背景。

在此处输入图像描述

I saw this question:我看到了这个问题:
How do you draw a border around a DataGridView cell while it's being edited? 在编辑 DataGridView 单元格时如何在其周围绘制边框?
I cannot implement this because the DataGrid doesn't have a CellPainting event.我无法实现这一点,因为 DataGrid 没有CellPainting事件。
Trying something different, I have an error on .Selected :尝试不同的东西,我在.Selected上有一个错误:

if (e.ColumnIndex != -1 && 
    e.RowIndex != -1 && dataGridView1[e.ColumnIndex, e.RowIndex].Selected)

This Grid looks like a Custom Control derived from the old DataGrid control.此 Grid 看起来像从旧DataGrid控件派生的自定义控件。

Since, based on comments, this appears to be the case, there's not really much to work with.因为,根据评论,情况似乎是这样,所以没有太多的工作要做。
Subscribe to the Paint and Scroll events using the event handlers shown here, this allows to draw a rectangle along the borders of the selected Row, considering the Scroll offset and the vertical ScrollBar width (the ScrollBars are child controls of the DataGrid, not necessarily of the default size, usually returned by SystemInformation.VerticalScrollBarWidth ).使用此处显示的事件处理程序订阅PaintScroll事件,这允许沿所选行的边界绘制一个矩形,考虑到 Scroll 偏移和垂直 ScrollBar 宽度(ScrollBars 是 DataGrid 的子控件,不一定是默认大小,通常由SystemInformation.VerticalScrollBarWidth返回)。

You may not be able to:您可能无法:

  • cast DotKasa.Kontrole.MyDataGrid directly to DataGrid .DotKasa.Kontrole.MyDataGrid直接转换为DataGrid If you cannot, add the DataGrid Control to your Project's ToolBox (open the ToolBox, right-click inside it, select Choose Items... , find the DataGrid and tick it).如果不能,请将 DataGrid 控件添加到项目的工具箱中(打开工具箱,在其中右键单击,select Choose Items... ,找到 DataGrid 并勾选它)。
  • use some of the native methods/properties shown here: the Custom Control may have hidden or overriden some of these to change the behavior without calling base .使用此处显示的一些本机方法/属性:自定义控件可能已隐藏或覆盖其中一些以更改行为而无需调用base

Add this code to your Form and see how it goes:将此代码添加到您的表单中,看看它是如何进行的:

int dataGridPenSize = 3;

private void MyDataGrid_Paint(object sender, PaintEventArgs e)
{
    var rect = GetDataGridCurrentRowRect(sender as DataGrid);
    if (rect != Rectangle.Empty) {
        using (var pen = new Pen(Color.Red, dataGridPenSize)) {
            e.Graphics.DrawRectangle(pen, rect);
        }
    }
}

private void MyDataGrid_Scroll(object sender, EventArgs e) 
    => (sender as Control).Invalidate();

private Rectangle GetDataGridCurrentRowRect(DataGrid dg)
{
    int scrollbarWidth = GetVerticalScrollBarWidth(dg);
    var bounds = dg.GetCurrentCellBounds();
    int upperLimit = dg.PreferredRowHeight + (dg.CaptionVisible ? dg.CaptionFont.Height + 4 : 0);
    if (bounds.Y <= upperLimit) return Rectangle.Empty;
    var rect = new Rectangle (
        new Point(dg.RowHeaderWidth, bounds.Y), 
        new Size(dg.PreferredSize.Width - dg.RowHeaderWidth - dataGridPenSize - scrollbarWidth, bounds.Height));
    return rect;
}

private int GetVerticalScrollBarWidth(DataGrid dg) {
    var vScroll = dg.Controls.OfType<VScrollBar>().FirstOrDefault();
    return vScroll == null ? 0 : vScroll.Width; 
}

To have full control on appearance of the rows and columns, you usually need to create custom column styles by driving from one of the existing built-in column styles like DataGridTextBoxColumn or DataGridBoolColumn or the base DataGridColumnStyle .要完全控制行和列的外观,您通常需要从现有的内置列 styles 之一(如DataGridTextBoxColumnDataGridBoolColumn或基本DataGridColumnStyle )驱动来创建自定义列 styles。 Then you can customize the behavior by overriding properties and methods of the class.然后,您可以通过覆盖 class 的属性和方法来自定义行为。

You will find this article very useful:你会发现这篇文章非常有用:

Example - Draw Border for DataGrid Row示例 - 为 DataGrid 行绘制边框

在此处输入图像描述

private void Form1_Load(object sender, EventArgs e)
{
    var dt = new DataTable();
    dt.Columns.Add("Id", typeof(int));
    dt.Columns.Add("Name", typeof(string));
    dt.Rows.Add(1, "A");
    dt.Rows.Add(2, "B");
    dt.Rows.Add(3, "C");

    var dg = new DataGrid();
    dg.Dock = DockStyle.Fill;
    var ts = new DataGridTableStyle();
    ts.GridColumnStyles.Add(new MyDataGridTextBoxColumn()
    { MappingName = "Id", HeaderText = "Id" });
    ts.GridColumnStyles.Add(new MyDataGridTextBoxColumn()
    { MappingName = "Name", HeaderText = "Name" });
    dg.TableStyles.Add(ts);

    this.Controls.Add(dg);
    dg.DataSource = dt;
}
public class MyDataGridTextBoxColumn : DataGridTextBoxColumn
{
    protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager 
        source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
    {
        base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
        if (this.DataGridTableStyle.DataGrid.CurrentRowIndex == rowNum)
        {
            g.DrawLine(Pens.Red, bounds.Left - 1, bounds.Top,
                bounds.Right + 1, bounds.Top);
            g.DrawLine(Pens.Red, bounds.Left - 1, bounds.Bottom -1 , 
                bounds.Right + 1, bounds.Bottom - 1);
        }
    }
}

I tried something out and it works nearly like you wanted.我尝试了一些东西,它几乎像你想要的那样工作。

You can get acces to the bounds rectangle for each cell where you want to paint the borders red with this function:您可以使用此 function 访问要在其中将边框涂成红色的每个单元格的边界矩形:

dataGridView1.GetCellDisplayRectangle(ColumnIndex, RowIndex, true)

I created a public rectangle list where i put all cellborder-rectangles i want to draw red.我创建了一个公共矩形列表,我将所有要绘制红色的单元格边框矩形放在其中。

public List<Rectangle> rectlist = new List<Rectangle>();

Then i added the datagridview_cellclick event and the datagridview_paint event and put following code in there:然后我添加了 datagridview_cellclick 事件和 datagridview_paint 事件,并在其中放入以下代码:

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        rectlist.Clear();

        for(int i = 0; i < dataGridView1.Columns.Count; i++)
        {
            rectlist.Add(dataGridView1.GetCellDisplayRectangle(i, e.RowIndex, true));
            
        }
        dataGridView1.Refresh();
    }

    private void dataGridView1_Paint(object sender, PaintEventArgs e)
    {
        foreach(Rectangle rect in rectlist)
        {
            e.Graphics.DrawRectangle(Pens.Red, rect);
        }
    }

Everytime you click on a cell, this code will put all cell-border-rectangles from cells off the same row in the list.每次单击单元格时,此代码都会将单元格中的所有单元格边框矩形放在列表的同一行中。 The datagridview.refresh() function will then call the datagridview_paint function.然后 datagridview.refresh() function 将调用 datagridview_paint function。 There you can draw the rectangles on the datagridview with the painteventargs.在那里,您可以使用painteventargs 在datagridview 上绘制矩形。 The only negative thing about this solution is, that the whole border of each cell is painted red.这个解决方案唯一的缺点是,每个单元格的整个边界都被涂成红色。

It looks like this: dgv with red borders它看起来像这样:带有红色边框的 dgv

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM