简体   繁体   中英

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

在此处输入图像描述 I have an custom control derived from the old 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).
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?
I cannot implement this because the DataGrid doesn't have a CellPainting event.
Trying something different, I have an error on .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.

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 ).

You may not be able to:

  • cast DotKasa.Kontrole.MyDataGrid directly to 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).
  • 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 .

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 . Then you can customize the behavior by overriding properties and methods of the class.

You will find this article very useful:

Example - Draw Border for DataGrid Row

在此处输入图像描述

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:

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:

        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. There you can draw the rectangles on the datagridview with the painteventargs. 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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