Reputation: 5093
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?
Upvotes: 23
Views: 40325
Reputation: 49
To do wrapping add this after binding
DataGrid1.ItemStyle.Wrap = true;
Upvotes: 0
Reputation: 39
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;
}
}
}
Upvotes: 1
Reputation: 1
I agree with the answer that discussed simply setting the WordWrap
on the cell and would add to it this scenario.
I was needing to change the colors and font styles on the fly based on the data in each cell. Initially I thought that I was stuck figuring out how to make the DrawString
work with wrapping inside CellPainting
event due to needing different text colors.
However, in the end I just set the Cell.Style
properties inside the CellPainting
event and then exited the event without setting the e.Handled = true
. This way the grid's paint event used the styles I set for each cell and the text wrapped properly.
For example:
datagrid1[e.ColumnIndex, e.RowIndex].Style.BackColor = Color.Green;
Upvotes: -1
Reputation: 2802
There is no need to reinvent the wheel by repainting the cell.
Instead simply:
AutoSizeRowsMode
property to AllCells
. This allows row height to
grow with any wrapped text. DataGridView.DefaultCellStyle.WrapMode
to DataGridViewTriState.True
to wrap text in the cells. DataGridView.AutoSizeColumnsMode
to
DataGridViewAutoSizeColumnsMode.None
so that the columns don't resize themselves
(so they remain at the user specified width).After that the text should wrap to the next line if there is not enough space in the column.
Upvotes: 22
Reputation: 1647
I've found @DeveloperX answer really useful, but with a couple of hiccups:
And it also caused missing cell borders (but this depends on grid/cell border settings).
I did a rework of @DeveloperX code to solve this issues, and came up with the following code:
private int _rowMaxHeight = 0;
private int _rowDefaultHeight = 0;
private void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.Value == null || e.RowIndex < 0)
{
// The WordWrap code is ony executed if requested the cell has a value,
// and if this is not the heading row.
return;
}
if (e.ColumnIndex == 0)
{
// Resetting row max height on each row's first cell
_rowMaxHeight = 0;
if (_rowDefaultHeight == 0)
{
/* The default DataGridView row height is saved when the first cell
* inside the first row is populated the first time. This is later
* used as the minimum row height, to avoid
* smaller-than-default rows. */
_rowDefaultHeight = dataGridView1.Rows[e.RowIndex].Height;
}
}
// Word wrap code
var sOriginal = e.Graphics.MeasureString(e.Value.ToString(),
dataGridView1.Font);
var sWrapped = e.Graphics.MeasureString(e.Value.ToString(),
dataGridView1.Font,
// Is is MeasureString that determines the height given the width, so
// that it properly takes the actual wrapping into account
dataGridView1.Columns[e.ColumnIndex].Width);
if (sOriginal.Width != dataGridView1.Columns[e.ColumnIndex].Width)
{
using (Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor),
fontBrush = new SolidBrush(e.CellStyle.ForeColor))
{
e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
// The DrawLine calls restore the missing borders: which borders
// miss and how to paint them depends on border style settings
e.Graphics.DrawLine(new Pen(gridBrush, 1),
new Point(e.CellBounds.X - 1,
e.CellBounds.Y + e.CellBounds.Height - 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y + e.CellBounds.Height - 1));
e.Graphics.DrawLine(new Pen(gridBrush, 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y - 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y + e.CellBounds.Height - 1));
//Updating the maximum cell height for wrapped text inside the row:
// it will later be set to the row height to avoid the flickering
// that would occur by setting the height multiple times.
_rowMaxHeight = (Math.Ceiling(sWrapped.Height) > _rowMaxHeight)
? (int)Math.Ceiling(sWrapped.Height) : _rowMaxHeight;
// The text is generated inside the row.
e.Graphics.DrawString(e.Value.ToString(), dataGridView1.Font,
fontBrush, e.CellBounds, StringFormat.GenericDefault);
e.Handled = true;
}
}
if (e.ColumnIndex == dataGridView1.ColumnCount -1
&& _rowMaxHeight > 0
&& _rowMaxHeight != dataGridView1.Rows[e.RowIndex].Height)
{
// Setting the height only in the last cell, when the full row has been
// painted, helps to avoid flickering when more than one row
// needs the wrap.
dataGridView1.Rows[e.RowIndex].Height =
(_rowMaxHeight > _rowDefaultHeight)
? _rowMaxHeight : _rowDefaultHeight;
}
}
Note that there is one problem still unresolved with this code: the text is not vertically centered anymore inside the cells!
Upvotes: 3
Reputation: 4683
May be handling cell painting event can help you
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.Value == null)
return;
var s = e.Graphics.MeasureString(e.Value.ToString(), dataGridView1.Font);
if (s.Width > dataGridView1.Columns[e.ColumnIndex].Width)
{
using (
Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
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 = (int)(s.Height * Math.Ceiling( s.Width / dataGridView1.Columns[e.ColumnIndex].Width)) ;
e.Handled = true;
}
}
}
Upvotes: 3
Reputation: 38200
Does setting this value help in achieving the display as you want
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
in addition to setting the WrapMode = DataGridViewTriState.True;
Upvotes: 2
Reputation: 46395
Try setting
.AutoSizeMode
to .DisplayedCells
. AutoSizeRowsMode
to AllCells
. DataGridView.DefaultCellStyle.WrapMode
to DataGridViewTriState.True
Upvotes: 18
Reputation: 108937
You can try setting the DataGridView.DefaultCellStyle.WrapMode
to DataGridViewTriState.True
Upvotes: 4