Home   |  Articles   |  Resources   |  Humor   |  Feedback       

  Login   Register 

Ads Via DevMavens


Auto Resizing Columns In A Windows Form DataGrid

Posted by on Sunday, December 28, 2003

Two methods to auto resize the width of columns in a Windows Form datagrid. The first assumes the DataSource is a DataTable, the second uses reflection.

At one point in the beta for .NET, I am sure I remember the DataGrid having an auto size property of some sort. This made all of the columns of a DataGrid wide enough to display the full text for every cell it contains. I am also sure this functionality is not in the release version. I can’t think of a reason why it might have been removed, except perhaps it was a performance and resource drain. Nevertheless, I know people need this functionality – me for one. One solution could look like the following code.

protected void SizeColumns(DataGrid grid)
{
  Graphics g = CreateGraphics();  

  DataTable dataTable = (DataTable)grid.DataSource;

  DataGridTableStyle dataGridTableStyle = new DataGridTableStyle();

   dataGridTableStyle.MappingName = dataTable.TableName;

  foreach(DataColumn dataColumn in dataTable.Columns)
  {
    int maxSize = 0;

    SizeF size = g.MeasureString(
                    dataColumn.ColumnName,
                    grid.Font
                 );

     if(size.Width > maxSize)
      maxSize = (int)size.Width;

    foreach(DataRow row in dataTable.Rows)
    {
      size = g.MeasureString(
                row[dataColumn.ColumnName].ToString(),
                grid.Font
          );

       if(size.Width > maxSize)
        maxSize = (int)size.Width;
    }

    DataGridColumnStyle dataGridColumnStyle =  new DataGridTextBoxColumn();
    dataGridColumnStyle.MappingName = dataColumn.ColumnName;
    dataGridColumnStyle.HeaderText = dataColumn.ColumnName;
    dataGridColumnStyle.Width = maxSize + 5;
    dataGridTableStyle.GridColumnStyles.Add(dataGridColumnStyle);
  }
  grid.TableStyles.Add(dataGridTableStyle);          

  g.Dispose();
}

If you are binding to an ArrayList or other custom collection implementing IList, try the more generic code below. I'd like to hear if it works or doesn't work for you. I've tested the code with DataTable and ArrayList DataSources, and learned quite a bit about Windows forms data binding.

I implemented this method in a class derived from DataGrid because originally I was counting on getting to some protected members of DataGrid for help, but as it turns out the whole process completes just using reflection on the DataSource. After reading some documentation and looking at the DataGrid with the Reflector tool, I'm pretty sure this is what the DataGrid does under the covers in any case.

The last item I needed to figure out was how to determine the MappingName property. The very next day a Chris Sells blog entry provides the answer from inside Microsoft.

public void AutosizeColumns()
{
   IList list = null;
   if(DataSource is IList)
   {
      list = (IList)DataSource;
   }
   else if(DataSource is IListSource)
   {
      list = ((IListSource)DataSource).GetList();
   }     

   if(list == null || list.Count < 0)
   {
      return;
   }
   
   PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(list[0]);	
   DataGridTableStyle dataGridTableStyle = new DataGridTableStyle();         
   dataGridTableStyle.MappingName = GetMappingName(list);

   using(Graphics g = CreateGraphics())
   {
      for(int i = 0; i < pdc.Count; i++)
      {
         SizeF maxSize = g.MeasureString(pdc[i].DisplayName, Font);
        
         foreach(object o in list)
         {
            object result = pdc[i].GetValue(o);
            string value = pdc[i].Converter.ConvertToString(result);

            SizeF size = g.MeasureString(value, Font);
            if(size.Width > maxSize.Width)
               maxSize = size;
         }

         DataGridColumnStyle dataGridColumnStyle = new DataGridTextBoxColumn(
         dataGridColumnStyle.MappingName = pdc[i].Name;
         dataGridColumnStyle.HeaderText = pdc[i].DisplayName;
         dataGridColumnStyle.Width = (int)(maxSize.Width + 5);
         dataGridTableStyle.GridColumnStyles.Add(dataGridColumnStyle);
      }
      TableStyles.Add(dataGridTableStyle);
   }
}

protected string GetMappingName(IList list)
{
   string result;

   if(list is ITypedList)
   {
      result = ((ITypedList)list).GetListName(null);
   }
   else
   {
      result = list.GetType().Name;
   }

   return result;
}

Comments:

DataGrid.DataSource
By JohnBourne on 1/20/2004
I also desired this functionality and spent a lot of effort trying to achieve it universally.

<Excerpt from AA Meeting>Hi, My name is John Bourne and I'm a failure.

In this case I failed because I found no way to operate on a datagrid without making assumptions as to the DataSource property of the DataGrid.

The DataGrid works equally well with a DataTable (as in your example) as it does with a EmployeeList (in which case it displays the public properties within the objects in the list). However there does not appear to be a single common interface that all "DataSource-able" objects have in common.

I was almost in "success mode" when I came across the infamous "Can't derive from this special class" condition.

Any thoughts on how to make this techique work for all possible DataSource-able objects?

IList !!
By scott on 1/20/2004
JB: Now that is a very insightful question, and it took some hacking around. A DataSource in winforms has to implement IList or IListSource, neither of which give you much to go on. I'm pretty sure the grid is using reflection to find things out, so I tried the same. I updated the article with some more generic code at the bottom. The only part that bothers me is you have to pass the MappingName as a param to use. The DataGrid obviously figures this out, perhaps it's just a switch statement. If DataSource is a table it uses DataTable.TableName, else it uses DataSource.GetType().ToString().

I'm very interested to know if this works for you. Keep that VC money rolling in and lay off the booze.

... and a completely different approach
By JohnBourne on 1/26/2004
To totally go another way, I played some with programmatically creating a "double-click" event on the column header separators. Worked (to a point). Unfortunately, you cannot (even programmatically) double click the separator between columns that are outside the viewable area of the datagrid (in other words you need to scroll). Meanwhile... I'm going to scroll over to the bar for more booze.

how to auto resize the datagrid completely?
By mamta on 8/26/2004
I would like to know the code for auto resizing the datagrid completely depending upon the browser size.
Like when I maximize my browser the datagrid should also expand.
how do I do this?

re: how to auto resize the datagrid completely?
By scott on 3/23/2005
In the browser I'm assuming you are using a web form's DataGrid. These will automatically expand column width.

Copyright 2004 OdeToCode.com 


The Blogs
Subscribe to the OdeToCode blogs for the latest news, downloads, new articles, and quirky commentary.
New Articles
C# 3.0 and LINQ
C# 3.0 introduced a number of new features for LINQ. In this article we'll examine the new features like extension methods, lambda expressions, anonymous types, and more.

Introduction To LINQ
This article is an introduction to LINQ and provides examples of using LINQ to query objects, XML, and relational data.

What ASP.NET Developers Should Know About JavaScript
This article looks at JavaScript from the perspective of a C# or Visual Basic programmer. See how to apply object oriented techniques to your JavaScript code.

Most Popular Articles
Master Pages In ASP.NET 2.0
Master pages in ASP.NET are the key to building a professional web application with a consistent, easy to maintain layout.

ASP.Net 2.0 - Master Pages: Tips, Tricks, and Traps
MasterPages are a great addition to the ASP.NET 2.0 feature set, but are not without their quirks. This article will highlight the common problems developers face with master pages, and provide tips and tricks to use master pages to their fullest potential.

Table Variables In T-SQL
Table variables allow you to store a resultset in SQL Server without the overhead of declaring and cleaning up a temporary table. In this article, we will highlight the features and advantages of the table variable data type.

Contribute Code
Privacy
Consultancy