Google
WWW Yariv Hammer's Code Site

Thursday, January 05, 2006

Setting the Row Height of the Grid to Fit the Contents

Intorduction
It is very hard to set the row height of the DataGrid (Framework 1.1). Actually I was very surprised that it is not a built-in feature. Not only it is not built-in, but also it is a very non-trivial task.

Suppose I have a row with text containing the \n\r characters (meaning new line). In this case I need the row to have multiple lines. Try and put a text with this characters in a normal DataGrid - only the first row will appear, and the other lines can be reached by using the up and down arrw keys. I will show a way of showing all the lines.

The source code in this article was inspired from this article in CodeProject.

The Solution
If you followed my previous articles in my blog, you can guess that the solution involves ColumnStyles. You will need to create your own custom DataGridColumnStyle and use it in order to populate the grid. A reminder of ColumnStyles can be found here.

First, I implement a class called MultiLineColumnStyle derived from DataGridTextBoxColumn. This class has a property MultiLine which when set to true will show all the lines in the cell.
The trick of resizing the height of the row is in the GetMinimumHeight overrided method.
Here is the code
------------------------------------------------------------
public class MultiLineColumnStyle:DataGridTextBoxColumn
{
   public bool MultiLine
   {
      get
      { return _multiLine; }
      set
      { _multiLine = value; }
   }
   private int _currentCell = 0;
   private bool _multiLine = false;

   public void ResetIterations()
   {
      _currentCell = 0;
   }
   protected override int GetMinimumHeight()
   {
      if (!_multiLine)
         return base.GetMinimumHeight();
      // Get CurrencyManager
      CurrencyManager cur = (CurrencyManager)this.DataGridTableStyle.DataGrid.BindingContext[this.DataGridTableStyle.DataGrid.DataSource, this.DataGridTableStyle.DataGrid.DataMember];
      // Rows available?
      if(cur == null cur.Count == 0)
         return base.GetMinimumHeight();
      // Increment counter
      this._currentCell ++;
      // Initialize return value
      int retVal = base.GetMinimumHeight();
      // Calculate height of row at currentIteration 1
      retVal = this.CalcStringHeight(GetColumnValueAtRow(cur,currentCell - 1).ToString());
// Reset when last cell reached
      if(_currentCell == cur.Count)
         this.ResetIterations(); // sets currentIteration to 0
      return retVal;
   }
   private int CalcStringHeight(string s)
   {
      try
      {
         // Create graphics for calculation
         System.Drawing.Graphics g = this.TextBox.CreateGraphics();
         // Do measure, and add a bit (4 pixels for me)
         return (int)g.MeasureString(s,this.TextBox.Font).Height + 4;
      }
      catch
      {
         // Error, return default font height.
         return base.GetMinimumHeight();
      }
   }
}
------------------------------------------------------------
The GetMinimumHeight is called for each cell seperately starting with the topmost cell in the column. So the _currentCell variable is used to run through the cells - each call will increment this (thanks to the above website for the great idea).
Obtaining the CurrencyManager (to get the text of the cell) of the column is another problem, which is solved in a very long and not straight-forward way.
One last problem is the actual calculation of the height of the row which is done in the CalcStringHeight method - by using MeasureString method.

Indeed, very hard work!!!

Demo
Add to the main form of the application a DataGrid. Here is the Form.Load event handler:
---------------------------------------------------
private void Form1_Load(object sender, System.EventArgs e)
{
   DataTable dt = new DataTable("MyTable");
   dt.Columns.Add(new DataColumn("multiline",typeof(string)) );
   dataGrid1.DataSource = dt;
   DataRow dr;
   dr = dt.NewRow();
   dr["multiline"] = "vsvsdfsdf\n\rdfgdfgsd\n\rcvsdvgsf";
   dt.Rows.Add(dr);
   dr = dt.NewRow();
   dr["multiline"] = "gsddg\n\rasfsfswef";
   dt.Rows.Add(dr);

   DataGridTableStyle ts = new DataGridTableStyle();
   ts.MappingName = "MyTable";
   MultiLineColumnStyle cs = new MultiLineColumnStyle();
   
cs.MappingName = "multiline";
   cs.HeaderText = "multiline";
   cs.MultiLine = true;
   
ts.GridColumnStyles.Add(cs);
   dataGrid1.TableStyles.Add(ts);
}
-------------------------------------------------
Run the application, and you will see that all the rows have appropriate height.

0 Comments:

Post a Comment

<< Home

Feel free to use everything here. Add links to my site if you wish.

Do not copy anything to other sites without adding link to here.

All the contents of the site belong to Yariv Hammer.