Unwanted WPF grid splitter behavior
I have a simple grid with three columns (one of which contains a grid divider). When the grid is resized and the left column reaches its minimum width, instead of doing nothing, it increases the width of the right column. Can anyone help me stop this?
I am unable to set the max width of the right column as the grid itself changes as well.
Here is some sample code that shows the problem. Move your mouse over the red area while resizing:
XAML:
<Grid DockPanel.Dock="Top" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="200" Width="*" />
<ColumnDefinition Width="3" />
<ColumnDefinition MinWidth="120" Width="240" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" />
<DockPanel LastChildFill="True" Grid.Row="0" Grid.Column="2" >
<Rectangle DockPanel.Dock="Right" Width="20" Fill="Blue" />
<Rectangle Fill="Green" />
</DockPanel>
<GridSplitter Background="LightGray" Grid.Row="0" Grid.Column="1" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
source to share
This approach is a hack, but can be used for the desired effect. Try putting your event handler on the Window.SizeChanged event to set the maxWidth of the first column. For example:
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
int borderBuffer = 9;
// AppWindow Size Splitter Width Far Column Min FudgeFactor
Col0.MaxWidth = e.NewSize.Width - Col1.Width.Value - Col2.MinWidth - borderBuffer;
}
I needed to use this method to prevent a third-party control from being included in the top row of the grid due to unwanted boxing caused by the gridSplitter ignoring the min / max column width with the width set to "Auto". It may be necessary to change the border buffer for your case. BorderBuffer in my case didn't make any sense depending on the geometry / column / border width - it was just a magic number that worked for my layout.
If anyone can come up with a cleaner solution I would like to use it instead. This solution reminds me of a painful attempt to get VB6 to resize controls - yuck. But for now, it hits when items on the top row of my grid are hiding due to unexpected packaging.
source to share
I know this is a little late, but I just ran into this problem and here is my solution. Unfortunately it is not general enough, it only works for a 2 column grid, but it can probably be adapted further. However, it solves the described problem and mine of its own, so here goes:
The solution is a hack or workaround, however you want to call it. Instead of declaring MinWidth for the left and right columns, you declare MinWidth and MaxWidth for the first column. This means the GridSplitter will not move to the right of a specific location. So far, so good.
The next problem is that if we have a resizable container (window in my case), this is not enough. This means that we cannot increase the left column as much as we want, although there may be a lot of room for the second. Fortunately, there is a solution: bind to the Grid ActualWidth and use an addition converter. The transform parameter will actually be the desired MinWidth for the right column, obviously a negative value since we need to subtract it from the Grid Width. You can also use SubtractConvertor, but that is up to you.
Here goes the xaml and the code:
<Grid Background="{DynamicResource MainBackground}" x:Name="MainGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" MinWidth="100" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}, Converter={Converters:AdditionConverter}, ConverterParameter=-250}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<GridSplitter Width="3" VerticalAlignment="Stretch" Grid.Column="0"/>
<!-- your content goes here -->
</Grid>
and the converter:
[ValueConversion(typeof(double), typeof(double))]
public class AdditionConverter : MarkupExtension, IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double dParameter;
if (targetType != typeof(double) ||
!double.TryParse((string)parameter, NumberStyles.Any, CultureInfo.InvariantCulture, out dParameter))
{
throw new InvalidOperationException("Value and parameter passed must be of type double");
}
var dValue = (double)value;
return dValue + dParameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
#region Overrides of MarkupExtension
/// <summary>
/// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension.
/// </summary>
/// <returns>
/// The object value to set on the property where the extension is applied.
/// </returns>
/// <param name="serviceProvider">Object that can provide services for the markup extension.
/// </param>
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
#endregion
}
I hope this helps,
Mihai Drebot
source to share