37

What would be the best/right way to have a set of DataGrid columns have proportional width (Width="\*"), but to have their minimum width be at least the width of their content? At the moment, if I use Width="*", then the columns stay exactly proportional, but content gets cropped if the columns get too thin. If I use Width="Auto", then the columns size themselves perfectly to their content, but this makes them all different sizes.

What I want is really a combination of the two, like Width="\*", MinWidth="Auto" so that when there's extra width the columns will all space out to equal widths, but when the grid is made smaller, the content never gets cropped.

Sadly, MinWidth="Auto" doesn't exist, so I guess I need to bind the column's MinWidth property, but it's hard to figure out exactly what I would bind it to.

How do I tell WPF "MinWidth=" the width of the column's widest piece of content?

garfbradaz
  • 3,424
  • 7
  • 43
  • 70
Andy T
  • 1,901
  • 7
  • 20
  • 24

5 Answers5

22

I know its a bit late, but I found your question and programmed a pure-XAML solution.

 <ColumnDefinition Width="42*" MinWidth="{Binding Path=ActualWidth, ElementName=projectInfoHeader }"/> 

Where the ElementName points to the control taking up most of the space. Of course thats only possible to do with elements, that do have a limited width. If you do it for example for a GroupBox, than you can resize only to larger width and never resize to smaller one.

If you have several candidates for the value of MinWidth, you need to write yourself a IMultiValueConverter, which takes an object[], parses it to floats, and returns the maximum (its just 1 linq query if you use it only yourselves and don't need to handle bad usage of the converter)

This way also supports dynamic changing of the MinWidth.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Tomas Grosup
  • 6,396
  • 3
  • 30
  • 44
12

Set Width = "Auto" in XAML.

Then in the code:

MinWidth = ActualWidth
Width = new GridLength(1, GridUnitType.Star)
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Anon
  • 121
  • 1
  • 3
  • 1
    Worked for me. Loop through all the columns in the grid and execute the code above in all of them. put the loop in a handler for the grid's Loaded event – saus Feb 18 '11 at 00:12
  • took me awhile to figure out even with this help. See my answer at http://stackoverflow.com/questions/13631694/wpf-datagrid-column-width-auto-and-scrollbar – Brent Nov 29 '12 at 19:15
1

I also had problems to size Grid columns correctly inside the GridViewColumn. There were several things that I tried but then I found the UniformGrid. It was the ultimate solution for me. It just works. I haven't knew it before...seems that it doesn't exist in VS toolbox by default (?) and thus didn't know it even exists.

You can find more about UniformGrid from here.

Ollikat
  • 81
  • 6
0

You can create a dependency property (called e.g. HorizontalPropFillOfBlankSpace) for Grid control which will ensure what you need (columns with Width="*", but MinWidth to fit contents). Then you can apply it on any grid you want:

<Grid namespace:GridHelper.HorizontalPropFillOfBlankSpace="True">
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="Auto" />
   </Grid.ColumnDefinitions>
   ...

You can see an example of the implementation of this dependency property below. Only columns with Width="Auto" are automatically resized to fill gap space. It can be customized by you what you need.

public class GridHelper
{
   /// <summary>
   /// Columns are resized to proportionally fill horizontal blank space.
   /// It is applied only on columns with the Width property set to "Auto".
   /// Minimum width of columns is defined by their content.
   /// </summary>
   public static readonly DependencyProperty HorizontalPropFillOfBlankSpaceProperty =
      DependencyProperty.RegisterAttached("HorizontalPropFillOfBlankSpace", typeof(bool), typeof(GridHelper), new UIPropertyMetadata(false, OnHorizontalPropFillChanged));

   public static bool GetHorizontalPropFillOfBlankSpace(Grid grid)
      => (bool)grid.GetValue(HorizontalPropFillOfBlankSpaceProperty);

   public static void SetHorizontalPropFillOfBlankSpace(Grid grid, bool value)
      => grid.SetValue(HorizontalPropFillOfBlankSpaceProperty, value);

   private static void OnHorizontalPropFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   {
      if (!(d is Grid grid))
         return;

      if ((bool)e.NewValue)
      {
         grid.Loaded += Grid_Loaded;
      }
      else
      {
         grid.Loaded -= Grid_Loaded;
      }
   }

   private static void Grid_Loaded(object sender, RoutedEventArgs e)
   {
      if (!(sender is Grid grid))
         return;

      foreach (var cd in grid.ColumnDefinitions)
      {
         if (cd.Width.IsAuto && cd.ActualWidth != 0d)
         {
            if (cd.MinWidth == 0d)
               cd.MinWidth = cd.ActualWidth;
            cd.Width = new GridLength(1d, GridUnitType.Star);
         }
      }
   }
}
Marek S.
  • 11
  • 1
  • 2
-1

Give the column a name in the XAML:

<Grid>
      <Grid.ColumnDefinitions>
             <ColumnDefinition Width="*" Name="Col1"/>
             <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
</Grid>

Then set the MinWidth property in the code as shown below:

public MainWindow()
{
    InitializeComponent();

    Col1.MinWidth = 340; //enter desired minimum width here
}
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
danielcooperxyz
  • 960
  • 1
  • 13
  • 28