Ensuring text wraps in a dataGridView column

Viewed 36280

I have dataGridView with a particular column. When I write long text in dataGridView it shows me a shortened version, with ellipses, because the column isn't wide enough to display the entire string.

| textdsadasda...  |

What do I must to do if I want to dataGridView show this text in next line, or wrap the text?

| textdsadasda     |
| dasdasa          |  (continuation of line above)

How can this be done?

9 Answers

I found DeveloperX's answer to be very good. But I found I needed to tweak it a little. Firstly, I needed to ensure that the column in question was not in AutoSizeMode:

    if (dgv.Columns[e.ColumnIndex].AutoSizeMode != DataGridViewAutoSizeColumnMode.None)
        throw new InvalidOperationException(String.Format("dgv {0} AutoSizeMode <> 'None'", dgv.Columns[e.ColumnIndex].Name));

I also found that using

var s = e.Graphics.MeasureString(e.Value.ToString(), dataGridView1.Font);

returns a string length, which can't be used for comparison to ColumnWidth, which is given in pixels. So, using How can I convert a string length to a pixel unit?, I modified the above line of code to be

var s = e.Graphics.MeasureString(e.Value.ToString(), new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Pixel));

I also found that doing a direct comparison of widths was insufficient to determine when to prevent clipping - there were some edge cases that weren't being caught. So, I replaced

if (s.Width > dataGridView1.Columns[e.ColumnIndex].Width)

with a ratio comparison (cutoff value determined by experiment) :

if (e.Value.ToString().Length / (double)dataGridView1.Columns[e.ColumnIndex].Width >= .189)

Finally, the cell in the selected row was not hightlighted, so I added the following:

       SolidBrush backColorBrush;
        if (dataGridView1.SelectedRows[0].Index == e.RowIndex)
            backColorBrush = new SolidBrush(e.CellStyle.SelectionBackColor);
        else
            backColorBrush = new SolidBrush(e.CellStyle.BackColor);

Final code:

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.Value == null || e.RowIndex == -1)
        return;

    if (dataGridView1.Columns[e.ColumnIndex].AutoSizeMode != DataGridViewAutoSizeColumnMode.None)
        throw new InvalidOperationException(Format("dataGridView1 {0} AutoSizeMode <> 'None'", dataGridView1.Columns[e.ColumnIndex].Name));

    var s = e.Graphics.MeasureString(e.Value.ToString(), new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Pixel));
    if (e.Value.ToString().Length / (double)dataGridView1.Columns[e.ColumnIndex].Width >= .189)
    {
        SolidBrush backColorBrush;
        if (dataGridView1.SelectedRows[0].Index == e.RowIndex)
            backColorBrush = new SolidBrush(e.CellStyle.SelectionBackColor);
        else
            backColorBrush = new SolidBrush(e.CellStyle.BackColor);

        using (backColorBrush)
        {
            e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
            e.Graphics.DrawString(e.Value.ToString(), dataGridView1.Font, Brushes.Black, e.CellBounds, StringFormat.GenericDefault);
            dataGridView1.Rows[e.RowIndex].Height = System.Convert.ToInt32((s.Height * Math.Ceiling(s.Width / (double)dataGridView1.Columns[e.ColumnIndex].Width)));
            e.Handled = true;
        }
    }
}

To do wrapping add this after binding

DataGrid1.ItemStyle.Wrap = true;
Related