Reputation: 3498
Getting three columns have the same width is done by setting Width
to Auto
.
<Grid x:Name="myGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">One</Label>
<Label Grid.Row="0" Grid.Column="1" x:Name="label1">Two</Label>
<Label Grid.Row="0" Grid.Column="2">Three</Label>
</Grid>
I want to achieve that if middle column is collapsed or hidden that the other two take up remaining space and get equal width.
If I just set Visibility to Collapsed or Hidden because of the Width="*", the other two columns width stays the same.
<Label Grid.Row="0" Grid.Column="1" Visibility="Collapsed">Two</Label>
I achieved desired functionality by programatically setting second column width to auto, but am looking for some other solution (preferably xaml way one).
private void Button_Click(object sender, RoutedEventArgs e)
{
this.myGrid.ColumnDefinitions[1].Width = GridLength.Auto;
this.label1.Visibility = Visibility.Collapsed;
}
Upvotes: 9
Views: 3990
Reputation: 222
I ended up with an idea similar to h.m.i.13 answer. I created generic a converter that hides a column/row or displays it with a specific grid length value. The advantage is that it will work with more complex grids where not every row has a simple 1-star length.
public class BooleanToGridLengthConverter : IValueConverter
{
private readonly static GridLength DefaultLength = new GridLength(0, GridUnitType.Pixel);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not bool booleanValue ||
parameter is not string stringParameter)
{
return DefaultLength;
}
if (booleanValue && TryParseGridLength(stringParameter, out var gridLength))
{
return gridLength;
}
return DefaultLength;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private static bool TryParseGridLength(string stringValue, out GridLength gridLength)
{
gridLength = DefaultLength;
if (stringValue.Equals("Auto", StringComparison.OrdinalIgnoreCase))
{
gridLength = GridLength.Auto;
return true;
}
if (stringValue.EndsWith("*"))
{
double starCount = 1;
if (stringValue.Length > 1 && !double.TryParse(stringValue.AsSpan(0, stringValue.Length - 1), out starCount))
{
return false;
}
gridLength = new GridLength(starCount, GridUnitType.Star);
return true;
}
if (double.TryParse(stringValue, out var pixelValue))
{
gridLength = new GridLength(pixelValue, GridUnitType.Pixel);
return true;
}
return false;
}
}
And then the usage:
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="{Binding MyBooleanProperty, Converter={StaticResource BooleanToGridLength}, ConverterParameter=3*}"/>
</Grid.ColumnDefinitions>
Upvotes: 0
Reputation: 405
I'm late, but I want to present my solution, in case it is useful to anyone.
I use this converter
public class BooleanToAutoOrStarGridLengthConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool isStar)
return new GridLength(1, isStar ? GridUnitType.Star : GridUnitType.Auto);
return new GridLength(0, GridUnitType.Star);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is GridLength gridLength && gridLength.GridUnitType == GridUnitType.Star)
return true;
return false;
}
public override object ProvideValue(IServiceProvider serviceProvider) => this;
}
in XAML like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="{Binding IsSecondLabelVisible, Converter={BooleanToAutoOrStarGridLengthConverter}}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">One</Label>
<Label Grid.Row="0" Grid.Column="1" Visibility="{Binding IsSecondLabelVisible}">Two</Label>
<Label Grid.Row="0" Grid.Column="2">Three</Label>
Upvotes: 0
Reputation: 962
The desired behaviour can be achieved using a UniformGrid
.
Make sure to set the number of rows to 1.
<UniformGrid Rows="1">
<Label>One</Label>
<Label>Two</Label>
<Label>Three</Label>
</UniformGrid>
The remaining elements are evenly spaced.
<UniformGrid Rows="1">
<Label>One</Label>
<Label Visibility="Collapsed">Two</Label>
<Label>Three</Label>
</UniformGrid>
Upvotes: 12
Reputation: 3498
I added Xaml Binding as suggested by Rob like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="{Binding MiddleColumnWidth}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">One</Label>
<Label Grid.Row="0" Grid.Column="1" Visibility="{Binding IsSecondLabelVisible}">Two</Label>
<Label Grid.Row="0" Grid.Column="2">Three</Label>
Code behind xaml:
private bool ShowOnlyTwoColumns;
private GridLength MiddleColumnWidth
{
get
{
if (ShowOnlyTwoColumns)
return GridLength.Auto; // Auto collapses the grid column when label is collapsed
return new GridLength(1, GridUnitType.Star);
}
}
private Visibility IsSecondLabelVisible
{
get { return this.ShowOnlyTwoColumns ? Visibility.Collapsed : Visibility.Visible; }
}
Upvotes: 2