Text overflows for custom cell painting of DataGri

2020-03-26 05:05发布

问题:

Here is my cell painting method

DataGridView grid = (DataGridView)sender;

        if (e.RowIndex == -1 || e.ColumnIndex == -1) { return; }
        if ((grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value == null)) return;
        Brush gridBrush = new SolidBrush(GridList[0].GridColor),backColorBrush = new SolidBrush(e.CellStyle.BackColor);

        Pen gridLinePen = new Pen(gridBrush);

        // Erase the cell.
        e.Graphics.FillRectangle(backColorBrush, e.CellBounds);

        // Draw the grid lines (only the right and bottom lines;
        // DataGridView takes care of the others).
        e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left,e.CellBounds.Bottom - 1, e.CellBounds.Right - 1,e.CellBounds.Bottom - 1);
        e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1,e.CellBounds.Top, e.CellBounds.Right - 1,e.CellBounds.Bottom);
        // Draw the text content of the cell, ignoring alignment.
        if (e.Value != null)
        {

            Brush brush = new SolidBrush(Color.Red);
            Brush brush1 = new SolidBrush(Color.Black);
            String s = (String)e.Value;

            System.Drawing.Rectangle rect = e.CellBounds;
            List<int> pos = null;
            if (grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Tag!=null){
                pos = (List<int>)grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Tag;
            }

            String[] arr = s.Split('\n');
            SizeF stringSize = TextRenderer.MeasureText(e.Graphics, arr[0], e.CellStyle.Font, e.CellBounds.Size);

            float wid = stringSize.Height;
            int X,Y;

            for(int i=0;i<arr.Length;i++){
                if (pos==null||pos.IndexOf(i)==-1)
                {
                    X = (e.CellBounds.X);
                    Y = (e.CellBounds.Y + i * ((int)stringSize.Height));
                    TextRenderer.DrawText(e.Graphics, arr[i], e.CellStyle.Font, new Point(X, Y), SystemColors.ControlText);
                    //e.Graphics.DrawString(arr[i], e.CellStyle.Font, brush1, new PointF(X, Y), StringFormat.GenericDefault);
                }
                else
                {
                    X = (e.CellBounds.X);
                    Y = (e.CellBounds.Y + i * (int)stringSize.Height );
                    Brush brushForBox = new SolidBrush(Color.FromArgb(100, 120, 50,0));
                    e.Graphics.FillRectangle(brushForBox, X, Y, e.CellBounds.Width, (int)stringSize.Height);
                    TextRenderer.DrawText(e.Graphics, arr[i], e.CellStyle.Font, new Point(X, Y), SystemColors.ControlText);
                    //e.Graphics.DrawString(arr[i], e.CellStyle.Font, brush, new PointF(X, Y), StringFormat.GenericDefault);
                }
            }                   
        }
        //grid.InvalidateCell(-1, e.RowIndex);
        e.Handled = true;

now it works just fine but the text overflows for first and last cells. For example if if first cell in the dataGridView is partially visible then text is rendered in row header. Similarly for last cell in the row text flows out of it. Any suggestion/solution is appreciated.

回答1:

The CellPainting event will let you draw onto the whole visible area of the DataGridView, including all headers and excluding only scrollbars.

It does provide you with the Cell's area in the e.CellBounds rectangle but it will still let you draw outside of it.

To restrict your drawing to the Cell the simplest way is to change the e.Graphics.ClipBoundsto the cell's bounding rectangle; to make sure no overflow into the rowheaders can occur we restrict it to only start left of the rowheader, maybe like this:

int rhw = grid.RowHeadersWidth;
Rectangle clip = e.CellBounds;
if (e.CellBounds.X < rhw)
    clip = new Rectangle(rhw, clip.Y, clip.Width - rhw, clip.Height);
e.Graphics.SetClip(clip, CombineMode.Replace);

Now nothing you draw can overflow.

Notes:

  • You could also set the target rectangle for for both DrawText and DrawString, but drawing in different fonts will make that a bit harder.
  • For some reason the clipped region doesn't seem to work with TextRenderer.

Also note: I couldn't reproduce the effect of underflowing into the headers. I can imagine that it might come from the cell's top can lying in the negative if the top cell isn't quite fully visible. (My DGV only let's me scroll by integral rows, though.) To exclude these cases you may need to calculate a better clipping rectangle that only starts right below the header cells..