共用方式為


Auto-sizing the Silverlight DataGrid

This post has been updated to work with the RTW version of the Silverlight 2 DataGrid.  The code examples are not guaranteed to work with previous Beta versions of the DataGrid. Read more about the features that the Silverlight 2 DataGrid has to offer...

Auto-sizing the DataGrid

The Silverlight 2 DataGrid is auto-sized by default.  This means that if you put it in a Canvas or a StackPanel and don't specify a Height or Width, or a MaxHeight or MaxWidth, you will get a DataGrid that is sized to its contents. 

Warning: This can be dangerous however if you are working with a large (1000+ item) collection as the ItemsSource.  Since the DataGrid will grow to the size of its contents, and will create objects for each cell that it can show based on its height, it will literally create thousands of objects to display all of the data.  As you can guess this has app performance implications so you should avoid the combination of an auto-sized DataGrid and a large amount of data to display.  This isn't an issue of course if you specify a Height or MaxHeight for the DataGrid, or put it in a container such as a Grid that provides it with a size.

Since the default size for the DataGrid is auto you won't have write any code to get auto-sizing behavior, but if you do give the DataGrid a height or width, and then want to switch it back to auto-size at runtime, simply set that value to double.NaN which is WPF and Silverlight's way of having a FrameworkElement auto-size itself.

C#

 dataGrid1.Height = double.NaN;

VB

 DataGrid1.Height = Double.NaN

Auto-sizing Columns and Rows

In addition to the DataGrid auto-sizing itself, Columns and Rows are also auto-sized by default.  Like the DataGrid, rows are auto-sized in the same manner by setting the value to double.NaN while columns on the other hand are done slightly differetly.  If you have ever worked with the Grid control, you might have noticed that the Width property of its ColumnDefinitions is not of type double, but rather a struct called GridLength.  The reason for this is that unlike a FrameworkElement's Width or Height properties which only have the possible values of Auto or a numeric value, a ColumnDefinition's Width can be set to a numeric value, Auto, or Star.  DataGridColumn.Width follows a similar pattern where instead of being of type double, it is of type DataGridLength.

The possible values for DataGridLenth are:

  • Auto: This auto-sizes the column or row to grow to the size of the largest header or cell.  It is effectively a combination of the other two auto-size modes.  You might notice as you scroll when a new larger cell is encountered that this value increases.  It will however not decrease once that item is scrolled out of view.
  • SizeToHeader: This auto-sizes the column or row the grow to the size of the header.  This will ignore the contents of the cells when determining its size and will not change unless the size of the header changes.
  • SizeToCells: This auto-sizes the column or row to grow to the size of the largest visible cell.  It will ignore the header cell in this calculation.  You might notice as you scroll when a new larger cell is encountered that this value increases.  It will however not decrease once that item is scrolled out of view.
  • Numeric: Unlike the others this is not an enum value, but rather simply a numeric value such as 100.  This mode will behave the same way that Beta 1 did, however setting it in code behind is slightly different.

Setting these in XAML is straight forward other than that unfortunately just like GridLength, there is no Intellisense for the enum values since a number is a valid entry as well.

XAML

 <data:DataGrid x:Name="dataGrid1" AutoGenerateColumns="False">
    <data:DataGrid.Columns>
        <data:DataGridTextColumn Binding="{Binding}" 
            Width ="Auto"  Header="Auto"/>
        <data:DataGridTextColumn Binding="{Binding}" 
            Width ="SizeToHeader"  Header="Size to Header"/>
        <data:DataGridTextColumn Binding="{Binding}" 
            Width ="SizeToCells"  Header="Size to Cells"/>
        <data:DataGridTextColumn Binding="{Binding}" 
           Width ="50"  Header="Numeric"/>
    </data:DataGrid.Columns>
</data:DataGrid>

If you were to run the code above and give it a data source it would look something like this:

 AutoSizedColumns

As you can see, once you know the possible enum values, setting it in XAML is fairly simple, and the Beta 1 code of Width="100" just works.  When you are working in code behind however things get slightly more tricky.

If you wanted to write code to do the same as above:

C#

 DataGrid dataGrid1 = new DataGrid();
dataGrid1.AutoGenerateColumns = false;

DataGridTextColumn col1 = new DataGridTextColumn();
col1.Binding = new Binding();
col1.Width = DataGridLength.Auto; 
col1.Header = "Auto";
dataGrid1.Columns.Add(col1);
DataGridTextColumn col2 = new DataGridTextColumn();
col2.Binding = new Binding();
col2.Width = DataGridLength.SizeToHeader; 
col2.Header = "Size to Header";
dataGrid1.Columns.Add(col2);
DataGridTextColumn col3 = new DataGridTextColumn();
col3.Binding = new Binding();
col3.Width = DataGridLength.SizeToCells; 
col3.Header = "Size to Cells";
dataGrid1.Columns.Add(col3);
DataGridTextColumn col4 = new DataGridTextColumn();
col4.Binding = new Binding();
col4.Width = new DataGridLength(50); 
col4.Header = "Numeric";
dataGrid1.Columns.Add(col4);

dataGrid1.ItemsSource = "a b c d e f g h i j".Split();
LayoutRoot.Children.Add(dataGrid1);

VB

 Dim dataGrid1 As New DataGrid
dataGrid1.AutoGenerateColumns = False

Dim col1 As New DataGridTextColumn
col1.Binding = New Binding
col1.Width = DataGridLength.Auto
col1.Header = "Auto"
dataGrid1.Columns.Add(col1)
Dim col2 As New DataGridTextColumn
col2.Binding = New Binding
col2.Width = DataGridLength.SizeToHeader
col2.Header = "Size to Header"
dataGrid1.Columns.Add(col2)
Dim col3 = New DataGridTextColumn
col3.Binding = New Binding
col3.Width = DataGridLength.SizeToCells
col3.Header = "Size to Cells"
dataGrid1.Columns.Add(col3)
Dim col4 = New DataGridTextColumn
col4.Binding = New Binding
col4.Width = New DataGridLength(50) 
col4.Header = "Numeric"
dataGrid1.Columns.Add(col4)

dataGrid1.ItemsSource = "a b c d e f g h i j".Split()
LayoutRoot.Children.Add(dataGrid1)

The interesting line above is where the Numeric column's width is set to 50.  There are two ways to do this.  If you are working with doubles, you can create a new GridLength that takes a double in its constructor.  This is the most common and the easiest way to do it.  If however you are working with strings such as a value in a TextBox, you can use the ConvertFrom method on DataGridLengthConverter which takes an object and returns a GridLength.

Comments

  • Anonymous
    June 09, 2008
    PingBack from http://blogs.msdn.com/scmorris/archive/2008/06/10/what-s-new-in-the-silverlight-datagrid-in-beta-2.aspx

  • Anonymous
    June 10, 2008
    Lots of links again tonight: ToolTip Control by Martin Mihaylov, Scott Morrison(3) on DataGrid, VSM by

  • Anonymous
    September 08, 2008
    how to get rid of extra column in extreme right in datagrid?

  • Anonymous
    September 19, 2008
    Hi Scott, I have problem with resizing the DataGrid. In my program, I have a custom paging for my DataGrid. When the DataGrid (with e.g. 10 rows) is loading the first time, it has all the rows showing in the datagrid; but the problem is when it goes to the second page with taller cells, then the height of the DataGrid stays as the same size of the first page! I don't know how to fix it. I gave a fixed hieght to the DataGrid in the xaml, but it didn't work....

  • Anonymous
    October 14, 2008
    As you might have heard , we just released Silverlight 2 , and with it the first version of the Silverlight

  • Anonymous
    November 14, 2008
    Hi Scott, You show picture where are rows with different height at post http://blogs.msdn.com/scmorris/archive/2008/10/14/silverlight-2-datagrid-is-released.aspx. How can I make it?

  • Anonymous
    November 21, 2008
    This is good stuff! I would like to see an option of "Stretch" for a column, however. As Ananya asks above, I believe it's the same thing.. Perhaps two options:

  • Allow "Stretch" for a column to fill remaining space
  • Show the grid BG color where there are no visible columns I also notice that when using row headers, the grid lines get "pushed" off the right side. Interesting.
  • Anonymous
    December 02, 2008
    Hi Scott, How to wrap text in datagrid header?

  • Anonymous
    December 02, 2008
    As mentioned earlier... how can we get rid of the column to the right?  I'd like to "auto-size" the columns to fill the entire width of the datagrid.

  • Anonymous
    March 03, 2009
    I have this major WISH-LIST: Why can't we all have an auto-size feature in windows to optimize the grids of data to size to header content as well as the data content of the underlying data under the headers?  When-ever I am looking at data windows and want to view URLs and the data paths, I come across trying to resize all the contents to better view  the data. if there is no data in the column, often double clicking the header limit double arrow results in the header name being cut-off as in [header values] becoming [he...] while the resizing does not take into consideration that the header of the data needs to be visible even when the data is much shorter than the header. Can this issue be addressed in Windows 7 as well as other areas of programming of data grids? Thanks much; Sincerely; Michael L. Burdett michael.l.burdett@gmail.com