Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you draw a border around a DataGridView cell while it's being edited?

I would like to draw a red border around a DataGridView cell while it's being edited.

I've managed to draw a red border around the selected cell while it's not being edited using this code:

private void Form1_Load(object sender, EventArgs e)
{
    this.Width = 650;
    this.Height = 250;
    dataGridView1.Left = 5;
    dataGridView1.Top = 5;
    dataGridView1.Width = 600;
    dataGridView1.Height = 175;

    DataTable dt = new DataTable("Test Table");
    dt.Columns.Add("Column 1");
    dt.Columns.Add("Column 2");
    dt.Columns.Add("Column 3");
    dt.Columns.Add("Column 4");
    dt.Columns.Add("Column 5");
    dt.Rows.Add(dt.NewRow());
    dt.Rows.Add(dt.NewRow());
    dt.Rows.Add(dt.NewRow());
    dt.Rows.Add(dt.NewRow());
    dt.Rows.Add(dt.NewRow());
    dataGridView1.DataSource = dt;

    dataGridView1.AllowUserToAddRows = false;
    dataGridView1.AllowUserToDeleteRows = false;
    dataGridView1.MultiSelect = false;
    dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect;
    dataGridView1.DefaultCellStyle.SelectionBackColor = Color.White;
    dataGridView1.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(this.dataGridView1_CellPainting);
    dataGridView1.EditingControlShowing += new System.Windows.Forms.DataGridViewEditingControlShowingEventHandler(this.dataGridView1_EditingControlShowing);
}

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex != -1 && e.RowIndex != -1 && dataGridView1[e.ColumnIndex, e.RowIndex].Selected)
    {
        using (Brush borderBrush = new SolidBrush(Color.Red))
        {
            using (Pen borderPen = new Pen(borderBrush, 2))
            {
                Rectangle rectDimensions = e.CellBounds;
                rectDimensions.Width -= 2;
                rectDimensions.Height -= 2;
                rectDimensions.X = rectDimensions.Left + 1;
                rectDimensions.Y = rectDimensions.Top + 1;

                e.Graphics.DrawRectangle(borderPen, rectDimensions);

                e.Handled = true;
            }
        }
    }
}

Which produces this result:

Image1

However, when you edit a cell this happens:

Image2

It seems the EditingControl is drawing itself over the top of most of my red border. Unfortunately, I can't find a way to fix this so my red border will stay fully displayed at all times.

How can I do this???



Here's what I've tried so far:

1. Handling the EditingControlShowing() event to manually re-draw the border like this:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    Graphics gfx = e.Control.CreateGraphics();

    using (Brush borderBrush = new SolidBrush(Color.Red))
    {
        using (Pen borderPen = new Pen(borderBrush, 2))
        {
            Rectangle rectDimensions = e.Control.ClientRectangle;
            rectDimensions.Width -= 2;
            rectDimensions.Height -= 2;
            rectDimensions.X = rectDimensions.Left + 1;
            rectDimensions.Y = rectDimensions.Top + 1;

            gfx.DrawRectangle(borderPen, rectDimensions);
        }
    }
}

But this didn't draw anything. I tried a few variations of this but all of them still drew nothing here.


2. I then tried to handle the Paint() event of the EditingControl like this:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    e.Control.Paint -= new PaintEventHandler(dataGridView1_EditingControl_Paint);
    e.Control.Paint += new PaintEventHandler(dataGridView1_EditingControl_Paint);
}

void dataGridView1_EditingControl_Paint(object sender, PaintEventArgs e)
{
    MessageBox.Show("Starting EditingControl Paint() Event...");
}

But this event doesn't even fire. I later read somewhere that the EditingControl uses a normal TextBox, which doesn't fire the Paint() event because it's handled by Windows instead.


3. Finally, rather than trying to re-paint another border, I decided to try and hack around it by resizing the EditingControl to be smaller than my border in hopes the border would then show around it, like this:

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
    e.Control.Resize -= new EventHandler(dataGridView1_EditingControl_Resize);
    e.Control.Resize += new EventHandler(dataGridView1_EditingControl_Resize);
}

void dataGridView1_EditingControl_Resize(object sender, EventArgs e)
{
    dataGridView1.EditingControl.Left = 20;
}

However, that just gave me this result:

Image3

So the TextBox did move over to the Left, but it seems there is another control underneath it that is still blocking my red border. However, I can't find anyway to get access to that control to resize it so this didn't work for me either.


4. I also tried using the code from #1 above to re-draw the border in the Resize() event, but that still did nothing. Although, using dataGridView1.EditingControl.BackColor = Color.Red; did work so I can format some parts of the control here, but it seems trying to draw a border isn't one of them.

All I want to do is keep a red border showing around the cell while it's being edited. Do you know how I can do this?

like image 363
Calcolat Avatar asked Aug 22 '15 10:08

Calcolat


2 Answers

The most simple approach using your existing code is setting of the CellBorderStyle to Sunken as shown below:

dataGridView1.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.Sunken;

enter image description here

If you don't like Sunken, then you can achieve this by AdjustCellBorderStyle and DataGridViewAdvancedBorderStyle, in cell focus event change/customize the cell border style. Also take a look at: How to: Customize Cells and Columns in the Windows Forms DataGridView Control by Extending Their Behavior and Appearance.

I hope it w'd help you.

like image 118
NASSER Avatar answered Nov 06 '22 15:11

NASSER


It can be done using some settings and painting specific parts of cell. To so so:

First, set CellBorderStyle to Raised or Sunken in designer or simply in form load code:

this.dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.Raised;

Then draw cells using these specific ordered rules:

  1. Draw only grid content cells not ColumnHeader cells nor RowHeader
  2. When drawing selected cells, first paint all parts except borders using e.Paint(...); then draw borders yourself
  3. Set e.Handled=true to prevent default painting
  4. When drawing non-selected cells, first paint all parts except borders using e.Paint(...)
  5. Draw top border of cells of first row and left border of cells of first column using grid background color
  6. Draw bottom border of cells of last row and right border of cells of last column using grid line color
  7. Draw bottom border of cells of non-last row and right border of cells of non-last column using grid background color
  8. Draw top border cells of non-first row and left border of cells of non-last column using grid line color 9.Set e.Handled=true to prevent default painting

This is screenshot of result, after select

enter image description here

and here is screenshot of result, when editing cell

enter image description here

and here is the code of cell paint event:

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    //Draw only grid content cells not ColumnHeader cells nor RowHeader cells
    if (e.ColumnIndex > -1 & e.RowIndex > -1)
    {
        //Pen for left and top borders
        using (var backGroundPen = new Pen(e.CellStyle.BackColor, 1))
        //Pen for bottom and right borders
        using (var gridlinePen = new Pen(dataGridView1.GridColor, 1))
        //Pen for selected cell borders
        using (var selectedPen = new Pen(Color.Red, 1))
        {
            var topLeftPoint = new Point(e.CellBounds.Left, e.CellBounds.Top);
            var topRightPoint = new Point(e.CellBounds.Right - 1, e.CellBounds.Top);
            var bottomRightPoint = new Point(e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
            var bottomleftPoint = new Point(e.CellBounds.Left, e.CellBounds.Bottom - 1);

            //Draw selected cells here
            if (this.dataGridView1[e.ColumnIndex, e.RowIndex].Selected)
            {
                //Paint all parts except borders.
                e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

                //Draw selected cells border here
                e.Graphics.DrawRectangle(selectedPen, new Rectangle(e.CellBounds.Left, e.CellBounds.Top, e.CellBounds.Width - 1, e.CellBounds.Height - 1));

                //Handled painting for this cell, Stop default rendering.
                e.Handled = true;
            }
            //Draw non-selected cells here
            else
            {
                //Paint all parts except borders.
                e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);

                //Top border of first row cells should be in background color
                if (e.RowIndex == 0)
                    e.Graphics.DrawLine(backGroundPen, topLeftPoint, topRightPoint);

                //Left border of first column cells should be in background color
                if (e.ColumnIndex == 0)
                    e.Graphics.DrawLine(backGroundPen, topLeftPoint, bottomleftPoint);

                //Bottom border of last row cells should be in gridLine color
                if (e.RowIndex == dataGridView1.RowCount - 1)
                    e.Graphics.DrawLine(gridlinePen, bottomRightPoint, bottomleftPoint);
                else  //Bottom border of non-last row cells should be in background color
                    e.Graphics.DrawLine(backGroundPen, bottomRightPoint, bottomleftPoint);

                //Right border of last column cells should be in gridLine color
                if (e.ColumnIndex == dataGridView1.ColumnCount - 1)
                    e.Graphics.DrawLine(gridlinePen, bottomRightPoint, topRightPoint);
                else //Right border of non-last column cells should be in background color
                    e.Graphics.DrawLine(backGroundPen, bottomRightPoint, topRightPoint);

                //Top border of non-first row cells should be in gridLine color, and they should be drawn here after right border
                if (e.RowIndex > 0)
                    e.Graphics.DrawLine(gridlinePen, topLeftPoint, topRightPoint);

                //Left border of non-first column cells should be in gridLine color, and they should be drawn here after bottom border
                if (e.ColumnIndex > 0)
                    e.Graphics.DrawLine(gridlinePen, topLeftPoint, bottomleftPoint);

                //We handled painting for this cell, Stop default rendering.
                e.Handled = true;
            }
        }
    }
}
like image 10
Reza Aghaei Avatar answered Nov 06 '22 14:11

Reza Aghaei