What would be the best/right way to have a set of DataGrid
columns have proportional width (Width=\"\\*\"),
but to have their minimum
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
.
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.
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
}
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);
}
}
}
}
Set Width = "Auto"
in XAML.
Then in the code:
MinWidth = ActualWidth
Width = new GridLength(1, GridUnitType.Star)