Don't Wrap and don't Clip. Better using a (web) Tooltip
When the desired width of a Web DataGrid column and the size of the text don't get along very well, one of two things happens. Either the column is automatically enlarged to include all the text or the text wraps to the next line.
For some reason--it could just be me--I normally happen to dislike both. So I made a point to figure out a way to add an ellipsis to the text after a certain size and use a tooltip. Yep, exactly the same behavior you get for free from a WinForms treeview. By making some reasonable assumptions, I did it. Here's how. Assumptions are:
- The DataGrid has explicit font information like font name and size in points
- The column indicates its exact width in pixels
The first step is defining a ItemDataBound event handler to capture the string being displayed in the cell. This string is the full text for the cell--the one you have to clip and adorn with a tooltip. Based on font information, you calculate the width of the text in pixels and compare that to the expected width of the column. If the text is too large for the column, you add an ellipsis and wrap the text in a tag with a proper title attribute.
The code below demonstrate the key steps.
void ItemDataBound(object sender, DataGridItemEventArgs e)
{
// Get the string to be displayed
string title = GetTheString();
// Returns the updated text for the specified column
string newText = AdjustTextForDisplay(title, 1, grid);
// Set the text including the tooltip when necessary
e.Item.Cells[1].Text = newText;
}
string AdjustTextForDisplay(string text, int colIndex, DataGrid grid)
{
// Calculate the dimensions of the text with the current font
SizeF textSize = MeasureString(text, grid.Font);
// Compare the size with the column's width
int colWidth = (int) grid.Columns[colIndex].ItemStyle.Width.Value;
if(textSize.Width > colWidth)
{
// Get the exceeding pixels
int delta = (int) (textSize.Width - colWidth);
// Calculate the average width of the characters (approx)
int avgCharWidth = (int) (textSize.Width/text.Length);
// Calculate the number of chars to trim to stay in the fixed width (approx)
int chrToTrim = (int) (delta/avgCharWidth);
// Get the proper substring + the ellipsis
// Trim 2 more chars (approx) to make room for the ellipsis
string rawText = text.Substring(0, text.Length-(chrToTrim+2)) + "...";
// Format to add a tooltip
string fmt = "{1}";
return String.Format(fmt, text, rawText);
}
return text;
}
SizeF MeasureString(string text, FontInfo fontInfo)
{
SizeF size;
float emSize = Convert.ToSingle(fontInfo.Size.Unit.Value+1);
emSize = (emSize==0 ?12 :emSize);
Font stringFont = new Font(fontInfo.Name, emSize);
Bitmap bmp = new Bitmap(1000, 100);
Graphics g = Graphics.FromImage(bmp);
size = g.MeasureString(text, stringFont);
g.Dispose();
return size;
}
Here's a screenshot. (Hopefully...)