Don't Wrap and don't Clip. Better using a (web) Tooltip

Published 28 November 03 10:47 AM | despos

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...)

Comments

# RichB said on November 28, 2003 04:48 AM:

The Image points to localhost

# DinoE said on November 28, 2003 05:20 AM:

Ooops. Fixed.

# Michael Schwarz said on November 28, 2003 05:33 AM:

Very small image... cannot see details.... :(

Why do you don't use the CSS property TEXT-OVERFLOW??

CIAO
Michael

# Gilad said on November 28, 2003 05:40 AM:

Ever thought of using CSS for this, and reducing load on the server? :)

http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/textoverflow.asp

(works only in IE, i think)

# DinoE said on November 28, 2003 06:03 AM:

Text-Overflow is a certainly an option. However, it is not supported by all browsers (though this is probably a minor drawback now). In addition, it only adds an ellipsis. In addition, it doesn't give you a tooltip. My point was just having a tooltip ONLY if necessary.

# TrackBack said on November 28, 2003 06:35 AM:

Dewayne Mikkelson and his Radio WebDog, Shadow

# Gilad said on December 2, 2003 01:27 AM:

Alright, then build a simple client-side Javascript to implement this.
I see no reason why this job has to get done by the server :)

# Tom Fischer said on December 2, 2003 09:39 AM:

Nice idea, nice implementation.

And nice to see someone intelligent make HTML a little more intellegent!

# TrackBack said on December 4, 2003 04:09 PM:
# Ade Bullock said on December 5, 2003 10:55 AM:

How could I get this to work where we set the style using CssClass and a .css file. I can't find the correct FontInfo object as the ItemStyle doesn't get populated from the .css file. I don't want to hardcode the style for my grids (other than width).

# TrackBack said on December 17, 2003 06:59 PM:
# Nick Lucas said on January 7, 2004 07:08 AM:

I was a bit confused by the "title=GetTheString();" I guess this should be "title=e.Item.Cells[1].Text.Trim();" Also the "return String.Format(fmt,text,rawText)" is unnecessary as a "return rawText;" will do the same. Finally in the itembound code I added:

// Set the text including the tooltip when necessary
e.Item.Cells[1].Text = newText;
if(newText!=title)
{
e.Item.Cells[1].ToolTip=title;
}

This actually set the tootip text, this then works most of the time but trimming 3 extra characters is safer than 2 when adding the ellipsis.

# Nick Lucas said on January 7, 2004 07:08 AM:

I was a bit confused by the "title=GetTheString();" I guess this should be "title=e.Item.Cells[1].Text.Trim();" Also the "return String.Format(fmt,text,rawText)" is unnecessary as a "return rawText;" will do the same. Finally in the itembound code I added:

// Set the text including the tooltip when necessary
e.Item.Cells[1].Text = newText;
if(newText!=title)
{
e.Item.Cells[1].ToolTip=title;
}

This actually set the tootip text, this then works most of the time but trimming 3 extra characters is safer than 2 when adding the ellipsis.

# codewiz said on March 26, 2004 10:24 AM:

Unfortunately, this technique does not seem to work if the column is a hyperlink column. The text content for a hyperlink column is empty, all displayed text is in the anchor element, which does not appear to be available at the time of the itemdatabound event. I've tried looking at the itemcreated event, but no go. I am experimenting with the prerender event to see if this can offer some help.

# Johnnynine said on April 1, 2004 02:56 PM:

You can get the hyperlink info from the Controls collection in the cell:
e.Item.Cells[i].Controls

# Hussein said on April 10, 2004 04:49 PM:

why don't you use both: CSS for displaying ellipsis, and ItemDataBound for the tooltip feature.

# abdul said on June 23, 2004 08:11 PM:

can any body write the code in vb.net and using hyperlinkcolumn? i am have such difficulty in doint this. i appreciate this. thanks.

# abdul said on June 23, 2004 08:12 PM:

i was typing code like this, i have many invalid cast exceptions coming in. please tell me what i am doing wrong. thanks.

Private Sub dgQuestions_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs) Handles dgQuestions.ItemDataBound
Dim c As Control
Dim hyperLinkText As String
Dim i As Integer
i = 0
For Each c In e.Item.Cells(3).Controls
i = i + 1
If TypeOf (c) Is HyperLink Then
'Response.Write(CType(c, HyperLink).Text)
hyperLinkText = CType(c, HyperLink).Text
Dim newHyperLinkText As String
newHyperLinkText = AdjustTextForDisplay(hyperLinkText, 3, dgQuestions)
CType(c, HyperLink).Text = newHyperLinkText
End If
Next
End Sub
Private Function AdjustTextForDisplay(ByVal text As String, ByVal colIndex As Integer, ByVal grid As DataGrid)
'Calculate the dimensions of the text with the current font
Response.Write("AdjustTextForDisplay-IN")
Dim textSize As SizeF
textSize = MeasureString(text, grid.Font)
'Compare the size with the column's width
Dim colWidth As Integer
Dim a As DataGridColumnCollection = grid.Columns
Dim b As HyperLinkColumn
For Each b In a
Response.Write("inside for out side if")
Next
End Function
Private Function MeasureString(ByVal text As String, ByVal fontInfo As FontInfo)
Dim size As SizeF
Dim emSize As Double
emSize = Convert.ToSingle(fontInfo.Size.Unit.Value + 1)
If (emSize = 0) Then
emSize = 12
End If
Dim stringFont As Font
stringFont = New Font(fontInfo.Name, emSize)
Dim bmp As Bitmap
bmp = New Bitmap(1000, 100)
Dim g As Graphics
g = Graphics.FromImage(bmp)
size = g.MeasureString(text, stringFont)
g.Dispose()
Return size
End Function

# koljik said on June 14, 2007 02:27 PM:

<a href=" http://buy-neurontin.tlg.pl ">buy neurontin</a>

<a href=" http://buy-buspar.tlg.pl ">buy buspar</a>

<a href=" http://buy-ephedra.tlg.pl ">buy ephedra</a>

<a href=" http://buy-sonata.tlg.pl ">buy sonata</a>

<a href=" http://buy-butalbital.tlg.pl ">buy butalbital</a>

<a href=" http://buy-norvasc.tlg.pl ">buy norvasc</a>

<a href=" http://buy-tenuate.tlg.pl ">buy tenuate</a>

<a href=" http://buy-dianabol.tlg.pl ">buy dianabol</a>

<a href=" http://buy-premarin.tlg.pl ">buy premarin</a>

<a href=" http://buy-lorazepam.tlg.pl ">buy lorazepam</a>

<a href=" http://buy-atarax.tlg.pl ">buy atarax</a>

<a href=" http://buy-retin.tlg.pl ">buy retin</a>

<a href=" http://buy-hydrocodone.tlg.pl ">buy hydrocodone</a>

<a href=" http://buy-zocor.tlg.pl ">buy zocor</a>

<a href=" http://buy-effexor.tlg.pl ">buy effexor</a>

<a href=" http://buy-desyrel.tlg.pl ">buy desyrel</a>

<a href=" http://buy-nexium.tlg.pl ">buy nexium</a>

<a href=" http://buy-naprosyn.tlg.pl ">buy naprosyn</a>

<a href=" http://buy-alprazolam.tlg.pl ">buy alprazolam</a>

<a href=" http://buy-imitrex.tlg.pl ">buy imitrex</a>

<a href=" http://buy-lasix.tlg.pl ">buy lasix</a>

<a href=" http://buy-didrex.tlg.pl ">buy didrex</a>

<a href=" http://buy-zovirax.tlg.pl ">buy zovirax</a>

<a href=" http://buy-trimox.tlg.pl ">buy trimox</a>

<a href=" http://buy-diflucan.tlg.pl ">buy diflucan</a>

<a href=" http://buy-zyban.tlg.pl ">buy zyban</a>

<a href=" http://buy-bontril.tlg.pl ">buy bontril</a>

<a href=" http://buy-augmentin.tlg.pl ">buy augmentin</a>

<a href=" http://buy-vicodin.tlg.pl ">buy vicodin</a>

<a href=" http://buy-vaniqa.tlg.pl ">buy vaniqa</a>

<a href=" http://buy-viagra.tlg.pl ">buy viagra</a>

<a href=" http://buy-wellbutrin.tlg.pl ">buy wellbutrin</a>

<a href=" http://buy-mesterolone.tlg.pl ">buy mesterolone</a>

<a href=" http://buy-adipex.tlg.pl ">buy adipex</a>

<a href=" http://buy-claritin.tlg.pl ">buy claritin</a>

<a href=" http://buy-levaquin.tlg.pl ">buy levaquin</a>

<a href=" http://buy-echinacea.tlg.pl ">buy echinacea</a>

<a href=" http://buy-adderall.tlg.pl ">buy adderall</a>

<a href=" http://buy-condylox.tlg.pl ">buy condylox</a>

<a href=" http://buy-prilosec.tlg.pl ">buy prilosec</a>

<a href=" http://buy-fosamax.tlg.pl ">buy fosamax</a>

<a href=" http://buy-famvir.tlg.pl ">buy famvir</a>

<a href=" http://buy-prevacid.tlg.pl ">buy prevacid</a>

<a href=" http://buy-tramadol.tlg.pl ">buy tramadol</a>

<a href=" http://buy-prozac.tlg.pl ">buy prozac</a>

<a href=" http://buy-zoloft.tlg.pl ">buy zoloft</a>

<a href=" http://buy-ultram.tlg.pl ">buy ultram</a>

<a href=" http://buy-allegra.tlg.pl ">buy allegra</a>

<a href=" http://buy-cialis.tlg.pl ">buy cialis</a>

<a href=" http://buy-diazepam.tlg.pl ">buy diazepam</a>

<a href=" http://buy-celebrex.tlg.pl ">buy celebrex</a>

<a href=" http://buy-lortab.tlg.pl ">buy lortab</a>

<a href=" http://buy-flexeril.tlg.pl ">buy flexeril</a>

<a href=" http://buy-zylopim.tlg.pl ">buy zylopim</a>

<a href=" http://buy-zithromax.tlg.pl ">buy zithromax</a>

<a href=" http://buy-ionamin.tlg.pl ">buy ionamin</a>

<a href=" http://buy-ambien.tlg.pl ">buy ambien</a>

<a href=" http://buy-tylenol.tlg.pl ">buy tylenol</a>

<a href=" http://buy-levitra.tlg.pl ">buy levitra</a>

<a href=" http://buy-codeine.tlg.pl ">buy codeine</a>

<a href=" http://buy-cozaar.tlg.pl ">buy cozaar</a>

<a href=" http://buy-singulair.tlg.pl ">buy singulair</a>

<a href=" http://buy-evista.tlg.pl ">buy evista</a>

<a href=" http://buy-plavix.tlg.pl ">buy plavix</a>

<a href=" http://buy-celexa.tlg.pl ">buy celexa</a>

<a href=" http://buy-tamiflu.tlg.pl ">buy tamiflu</a>

<a href=" http://buy-vioxx.tlg.pl ">buy vioxx</a>

<a href=" http://buy-zyrtec.tlg.pl ">buy zyrtec</a>

<a href=" http://buy-meridia.tlg.pl ">buy meridia</a>

<a href=" http://buy-danazol.tlg.pl ">buy danazol</a>

<a href=" http://buy-carisoprodol.tlg.pl ">buy carisoprodol</a>

<a href=" http://buy-lipitor.tlg.pl ">buy lipitor</a>

<a href=" http://buy-testosterone.tlg.pl ">buy testosterone</a>

<a href=" http://buy-xenical.tlg.pl ">buy xenical</a>

<a href=" http://buy-ativan.tlg.pl ">buy ativan</a>

<a href=" http://buy-propecia.tlg.pl ">buy propecia</a>

<a href=" http://buy-phentermine.tlg.pl ">buy phentermine</a>

<a href=" http://buy-valium.tlg.pl ">buy valium</a>

<a href=" http://buy-cipro.tlg.pl ">buy cipro</a>

<a href=" http://buy-renova.tlg.pl ">buy renova</a>

<a href=" http://buy-xanax.tlg.pl ">buy xanax</a>

<a href=" http://buy-aristocort.tlg.pl ">buy aristocort</a>

<a href=" http://buy-tenormin.tlg.pl ">buy tenormin</a>

<a href=" http://buy-valtrex.tlg.pl ">buy valtrex</a>

<a href=" http://buy-paxil.tlg.pl ">buy paxil</a>

<a href=" http://buy-rogaine.tlg.pl ">buy rogaine</a>

<a href=" http://buy-soma.tlg.pl ">buy soma</a>

<a href=" http://buy-deltasone.tlg.pl ">buy deltasone</a>

<a href=" http://buy-fioricet.tlg.pl ">buy fioricet</a>

# TestName said on February 12, 2008 04:54 AM:

Test myfunction comment

# TestName said on March 6, 2008 12:07 PM:

Test myfunction comment

# TestName said on March 13, 2008 02:43 PM:

Test myfunction comment

# TestName said on March 14, 2008 02:27 PM:

Test myfunction comment

# TestName said on March 14, 2008 10:45 PM:

Test myfunction comment

# TestName said on March 15, 2008 07:09 AM:

Test myfunction comment

# TestName said on March 15, 2008 03:52 PM:

Test myfunction comment

# TestName said on March 16, 2008 12:06 AM:

Test myfunction comment

# TestName said on March 16, 2008 08:30 AM:

Test myfunction comment

# TestName said on March 16, 2008 05:15 PM:

Test myfunction comment

# TestName said on March 16, 2008 05:15 PM:

Test myfunction comment

# TestName said on March 17, 2008 10:20 AM:

Test myfunction comment

# TestName said on March 17, 2008 06:56 PM:

Test myfunction comment

# TestName said on March 18, 2008 11:58 AM:

Test myfunction comment

# TestName said on March 18, 2008 08:43 PM:

Test myfunction comment

# TestName said on March 19, 2008 05:11 AM:

Test myfunction comment

# TestName said on March 19, 2008 01:34 PM:

Test myfunction comment

# TestName said on March 19, 2008 10:12 PM:

Test myfunction comment

# TestName said on March 20, 2008 06:27 AM:

Test myfunction comment

# TestName said on March 20, 2008 02:59 PM:

Test myfunction comment

# TestName said on March 21, 2008 06:17 AM:

Test myfunction comment

# TestName said on March 22, 2008 05:33 AM:

Test myfunction comment

# TestName said on March 22, 2008 12:42 PM:

Test myfunction comment

# TestName said on March 22, 2008 07:34 PM:

Test myfunction comment

# TestName said on March 23, 2008 02:29 AM:

Test myfunction comment

# TestName said on March 23, 2008 09:19 AM:

Test myfunction comment

# TestName said on March 24, 2008 06:02 AM:

Test myfunction comment

# TestName said on March 24, 2008 08:26 PM:

Test myfunction comment

# TestName said on March 25, 2008 03:41 AM:

Test myfunction comment

# TestName said on March 25, 2008 12:12 PM:

Test myfunction comment

# TestName said on March 26, 2008 07:22 PM:

Test myfunction comment

# TestName said on March 27, 2008 06:01 AM:

Test myfunction comment

# TestName said on March 28, 2008 02:01 AM:

Test myfunction comment

# TestName said on March 28, 2008 09:47 AM:

Test myfunction comment

# TestName said on March 29, 2008 10:50 AM:

Test myfunction comment

# TestName said on March 31, 2008 05:52 PM:

Test myfunction comment

# TestName said on April 1, 2008 01:49 AM:

Test myfunction comment

# TestName said on April 1, 2008 11:02 AM:

Test myfunction comment

# TestName said on April 1, 2008 11:03 AM:

Test myfunction comment

# TestName said on April 2, 2008 10:25 PM:

Test myfunction comment

# TestName said on April 5, 2008 03:18 AM:

Test myfunction comment

Leave a Comment

(required) 
(required) 
(optional)
(required)