Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize WPF DataGrid to fit its content?

The aim

I would like to set such size for the DataGrid (standard, from WPF) so all cells (text) would be fully visible. I have window with DockPanel, with DataGrid in it, so when I resize the window, all nested widgets (DockPanel and DataGrid) are resized accordingly.

Example (edit-1)

Let's say you have window, 100 pixels wide and you have DataGrid with one column, which cell is "the quick brown fox..." (400 pixels wide). Thus the DataGrid should be resized to 400 pixels (probably more, because of padding) and the Window should be resized to 400 pixels too (also more, because of padding).

I didn't find any standard method to do it (AFAIK WPF provides way to clip the content to desired width, my problem is exactly opposite), so I come up with such ugly workaround, which does not work too well.

The workaround

  1. iterate over DataGrid headers (assuming they are just strings) and compute width required for the text
  2. iterate over DataGrid rows per each column (assuming they are TextBlock or TextBox) and compute the maximum width required for the text -- add horizontal paddings for TextBlock/TextBox and horizontal margins for DataGrid cell
  3. sum all differences between DataGrid ActualWidth for columns and the maximum width computed in (2)
  4. increase the window width by the difference computed in (3)

THE PROBLEM

I did several tests, and in some cases the computed width is too big (this is minor problem), for some cases is too small. The problem starts at its core procedure -- computing the required width for TextBox/TextBlock, computed width is always 1 unit less than it should be (if I set the width to computed one, 1 pixel from text is always clipped).

So which factor I am ignoring here? Or maybe better -- is there already some method to resize DataGrid to fit its content?

The code

Computing width required for text (here for TextBlock):

    public static double TextWidth(this TextBlock widget, string text)     {         var formattedText = new FormattedText(text, // can use arbitrary text                                               System.Globalization.CultureInfo.CurrentCulture,                                               widget.FlowDirection,                                               widget.FontFamily.GetTypefaces().FirstOrDefault(),                                               widget.FontSize,                                                widget.Foreground);          return formattedText.Width+widget.Padding.Left+widget.Padding.Right;     } 

Adjusting the Window size to fit DataGrid content (ugly_factor is ugly workaround ;-) since I didn't figure out how to fix it properly I set it to 1.3 and this way my window is "never" too small):

    public static void AdjustWidthToDataGrid(this Window window, DataGrid dataGrid, double ugly_factor)     {         var max_widths = dataGrid.Columns.Select(it => window.TextWidth(it.Header as string)                                                                          * ugly_factor).ToArray();          foreach (var row in Enumerable.Range(0, dataGrid.Items.Count))             foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))             {                 var cell = dataGrid.GetCell(row, col);                 double width = 0;                 if (cell.Content is TextBlock)                     width = (cell.Content as TextBlock).TextWidth();                 else if (cell.Content is TextBox)                     width = (cell.Content as TextBox).TextWidth();                  if (cell.Content is FrameworkElement)                 {                     var widget = cell.Content as FrameworkElement;                     width = width + widget.Margin.Left + widget.Margin.Right;                 }                  max_widths[col] = Math.Max(max_widths[col],                                             width*ugly_factor+cell.Padding.Left+cell.Padding.Right);             }          double width_diff = 0;          foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))             width_diff += Math.Max(0,max_widths[col] - dataGrid.Columns[col].ActualWidth);          if (width_diff > 0)             window.Width = window.ActualWidth+ width_diff;     } 
like image 538
greenoldman Avatar asked Jan 02 '11 10:01

greenoldman


People also ask

Can user resize columns WPF?

Column and Row Resizing | ComponentOne DataGrid for WPF and Silverlight. By default end users can resize columns and rows in the grid at run time.

What is SharedSizeGroup WPF?

You can use the SharedSizeGroup attribute to share column sizes across different grids. You can't normally share sizes of star-sized columns across multiple grids, however, since star sizing works only in the context of the current grid.

What is the difference between grid and DataGrid in WPF?

A Grid is a control for laying out other controls on the form (or page). A DataGrid is a control for displaying tabular data as read from a database for example.

Can user add rows DataGrid WPF?

WPF DataGrid (SfDataGrid) provides built-in row called AddNewRow. It allows user to add a new row to underlying collection. You can enable or disable by setting SfDataGrid.


1 Answers

I just came out of the same problem where I had to give options in a data grid's column to fit its width as per the content of both header and cell. I used the following code:

private void FitToContent()     {         // where dg is my data grid's name...         foreach (DataGridColumn column in dg.Columns)         {             //if you want to size your column as per the cell content             column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToCells);             //if you want to size your column as per the column header             column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToHeader);             //if you want to size your column as per both header and cell content             column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Auto);         }     } 

Also I provided an option on columns to fit as per the display (datagrid's width). for that I used the same code above with the following minor change:

column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Star);

FOR ALL COLUMNS : Make sure you keep HorizontalScrollVisibility to Auto.

like image 99
Sonal Savaratkar Avatar answered Sep 21 '22 18:09

Sonal Savaratkar