2

I have a datagridview that displays data but the data displayed doesn't fill the whole datagridview that the gray background of datagridview shows. what I want to happen is to show gridlines of the datagridview even with out data in each rows. enter image description here

luckily, I found a code regarding this, (this code is for AutoSizeColumnsMode property == Fill but I need this property to be set to AllCells for longer strings inside each columns) at first I thought that this is the code im looking for:

private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
    int rowHeight = this.dataGridView1.RowTemplate.Height;

    Pen slategraypen = new Pen(Brushes.SlateGray,0.5f);
    slategraypen.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel;
    slategraypen.Alignment = System.Drawing.Drawing2D.PenAlignment.Center;

    int h = this.dataGridView1.ColumnHeadersHeight + (rowHeight) * (this.dataGridView1.NewRowIndex);

    Bitmap rowImg = new Bitmap(this.dataGridView1.Width, rowHeight);

    Graphics g = Graphics.FromImage(rowImg);

    Rectangle rFrame = new Rectangle(1, 1, this.dataGridView1.Width-4, rowHeight);

    g.DrawRectangle(slategraypen, rFrame);

    Rectangle rFill = new Rectangle(2, 1, this.dataGridView1.Width - 4, rowHeight-1);

    g.FillRectangle(Brushes.White, rFill);

    // for rowheaders drawing. in my case, I dont want to show the rowheaders so I didnt include this in my code
    //Rectangle rowHeader = new Rectangle(2, 2, this.dataGridView1.RowHeadersWidth - 2, rowHeight - 4);

    //g.FillRectangle(new SolidBrush(this.dataGridView1.RowHeadersDefaultCellStyle.BackColor), rowHeader);

    int w = this.dataGridView1.RowHeadersWidth-40;// -40 is the width of the row header that I dont want to show

    for (int j = 0; j < this.dataGridView1.ColumnCount; j++)
    {
        w += this.dataGridView1.Columns[j].Width;
        g.DrawLine(slategraypen, new Point(w, 0), new Point(w, rowHeight));
    }

    int loop = (this.dataGridView1.Height - h) / rowHeight;

    for (int j = 0; j < loop + 1; j++)
    {
        e.Graphics.DrawImage(rowImg, 0, h + j * rowHeight);
    }
}

and this happened:

enter image description here

But, when I enter a long string in a column this happens: notice the right part of the datagridview, some columns shrink because of the fill property set for autosizecolumnsmode enter image description here

I tried to change AutoSizeColumnsMode property to allcells and this happened: whenever I scroll the horizontal scrollbar, the lines drawn below were being draw on the wrong places. im not quite sure if this will also happen if I scroll a vertical scrollbar up and down.

enter image description here

I need your help in writing the correct code for this. I would really appreciate your help.

Hossein Golshani
  • 1,847
  • 5
  • 16
  • 27
  • Why would you want this?? Drawing cells where there are none is tempting users to click there, no? If you want rows, add more rows! – TaW Oct 08 '18 at 14:47
  • i just dont want the gray part on the first picture to be shown. it just doesn't look nice to me seeing that gray part. and while surfing the net for an answer i found the code above on social.msdn.mircosoft.com. – newbie programmer Oct 08 '18 at 14:52
  • You can always change the backcolor to white.. Of course it can be coded correctly if the scrolling is factored in but imo it is still misleading. – TaW Oct 08 '18 at 14:55
  • oh yeah i tried changing it to white but didn't looked nice either. i want my datagridview to look like an excel sheet :) can you help me please? – newbie programmer Oct 08 '18 at 14:58
  • Is it read-only or disabled?? User will hate if it looks like an excel sheet but is actually dead.. – TaW Oct 08 '18 at 15:31
  • thank you TaW for your time and effort to help me with this one! but the same problem on the 4th picture above still occur. the cells that were drawn are still going to the wrong places when i scroll the horizontal scrollbar. – newbie programmer Oct 08 '18 at 16:52
  • I think I found the reason why you see artifacts, see the updated answer! (code the scroll event as suggested..!) – TaW Oct 08 '18 at 17:14
  • TaW the cause of the error on the old code was the RowHeadersVisible property set to false. When i set it to true ofcourse the rowheaders became visible and the lines were all fixed. But another problem arises. I need the rowheaders to be invisible. I dont know about the updated code below if it will still cause error even the rowheaders were not visible. – newbie programmer Oct 08 '18 at 17:34
  • It should work, it does here. The code is changed in the the cellpainting event and the scroll event is coded. – TaW Oct 08 '18 at 17:41
  • I think this is the last issue. It works perfectly fine when RowHeadersVisible property is set to True. But when I set it to False that is because i don't want to show the rowheaders, when i scroll to the right, all lines get messed up, but when i scroll back to left, all messed up lines disappear. I even coded the datagridview1.invalidate on scroll event. – newbie programmer Oct 08 '18 at 17:58
  • That sounds weird. It all works fine here with or without the rowheaders, scrolling left or right. Can you use the debugger to make sure the scroll is hit.? Did you make it doublebuffered? – TaW Oct 08 '18 at 18:05
  • Note that I have corrected a minor error wrt RowHeaders.. – TaW Oct 09 '18 at 14:55

1 Answers1

3

Here is a quick one:

enter image description here

I use the CellPainting to collect the current column positions. This little trick let's me ignore any scrolling, column resizing etc..

Here is how:

List<int> colX = new List<int>();

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.RowIndex == 0)
    {
        if (e.ColumnIndex == (dataGridView1.RowHeadersVisible ?  -1 : 0)) colX.Clear();
        colX.Add(e.CellBounds.X);
    }
}

And in the Paint event I draw the 'cells'.

using System.Drawing.Drawing2D;
..

private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
    Rectangle cRect = dataGridView1.ClientRectangle;
    int y0 = 0;
    if (dataGridView1.ColumnHeadersVisible) y0 += dataGridView1.ColumnHeadersHeight;
    int rhw = dataGridView1.RowHeadersVisible ? dataGridView1.RowHeadersWidth : 0;

    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
        y0 += row.Height;
    }
    int y1 = cRect.Height;
    using (SolidBrush brush = new SolidBrush(dataGridView1.DefaultCellStyle.BackColor))
        e.Graphics.FillRectangle(brush, cRect.Left + 2, y0, cRect.Right - 4, y1 - y0 - 2);
    using (Pen gridPen1 = new Pen(dataGridView1.GridColor, 1f) 
            { DashStyle = DashStyle.Dot })
    using (Pen gridPen2 = new Pen(dataGridView1.GridColor, 1f) 
            { DashStyle = DashStyle.Solid })
    {
        for (int i = 0; i < colX.Count; i++)
            e.Graphics.DrawLine(gridPen1, colX[i] - 1, y0, colX[i] - 1, y1);
        int y = y0;
        while (y < cRect.Bottom)
        {
            e.Graphics.DrawLine(y == y0 ? gridPen2 : gridPen1, 
                                cRect.Left, y, cRect.Right, y);
            y += dataGridView1.Rows[0].Height;
        }
        if (rhw > 0)  e.Graphics.DrawLine(gridPen1, rhw, y0, rhw, y1);

    }
}

Much simpler than the code you found, which has several other bugs, like leaking resources in a Paint event..

Note: I made the pseudo-cells stand out just a little by drawing with a dotted line..

Also note that the code assumes RowHeaders.

If you don't have them you should also Invalidate in the Scroll event:

private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
    dataGridView1.Invalidate();
}

Also do make the DGV DoubleBuffered to avoid flicker!!

Depending on your needs you may have to Invalidate in a few more events, like:

private void dataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
    dataGridView1.Invalidate();
}

Others may include ColumnAdded, ColumnRemoved..

Update: I have corrected a minor error wrt RowHeaders..

TaW
  • 53,122
  • 8
  • 69
  • 111