Search code examples
wpfxamlgridsplitter

WPF GridSplitter after resize


Once the gridsplitter is used to resize a grid the row * will not reclaim the space when the other rows are collapsed.

I have the following grid in a master detail view with three rows. A data grid on top a splitter in the middle and a contentcontrol view in the last row. The splitter has a close button on it to collapse the detail. This all works with the exception that once the user resizes using the gridsplitter.

    <Grid Margin="3,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Style="{StaticResource CollapsableRow}"/><!-- Splitter Here -->
        <RowDefinition Style="{StaticResource CollapsableRow}"/>
    </Grid.RowDefinitions>

The GridSplitter style:

    <Style x:Key="gridSplitterStyle" TargetType="{x:Type GridSplitter}">
    <Setter Property="Visibility" Value="{Binding IsItemSelected, Converter={StaticResource BoolToShow},ConverterParameter='Visible|Collapsed'}" />
    <Setter Property="Width" Value="Auto"/>
    <Setter Property="Height" Value="14"/>
    <Setter Property="HorizontalAlignment" Value="Stretch"/>
    <Setter Property="Border.BorderBrush" Value="#FF6593CF" />
    <Setter Property="Border.BorderThickness" Value="0,1,0,0" />
    <Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
    <Setter Property="UIElement.Focusable" Value="False" />
    <Setter Property="Control.Padding" Value="7,7,7,7" />
    <Setter Property="Cursor" Value="SizeNS" /></Style>

Like I said the collapse works correctly unless the gridsplitter is used to resize. After that the whitespace stays.

EDIT: H.B. and codenaked had simple and consistant suggestions so and I attempted to implement them w/o success in a data trigger:

<Style x:Key="CollapsableRow" TargetType="{x:Type RowDefinition}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding SelectedItem, Converter={StaticResource IsNullConverter}}" Value="True">
            <Setter Property="RowDefinition.Height" Value="0"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding SelectedItem, Converter={StaticResource IsNullConverter}}" Value="False">
            <Setter Property="RowDefinition.Height" Value="Auto"/>
        </DataTrigger>            
    </Style.Triggers>
</Style>   

Solution

  • Since the grid splitter and detail were already being hidden Visibility was the obvious choice to reset the next row definition height.

     /// <summary>
    /// Grid splitter that show or hides the following row when the visibility of the splitter is changed. 
    /// </summary>
    public class HidableGridSplitter : GridSplitter { 
    
        GridLength height;
    
        public HidableGridSplitter()
        {
            this.IsVisibleChanged += HideableGridSplitter_IsVisibleChanged;
            this.Initialized += HideableGridSplitter_Initialized;
        }
    
        void HideableGridSplitter_Initialized(object sender, EventArgs e)
        {
            //Cache the initial RowDefinition height,
            //so it is not always assumed to be "Auto"
            Grid parent = base.Parent as Grid;
            if (parent == null) return;
            int rowIndex = Grid.GetRow(this);
            if (rowIndex + 1 >= parent.RowDefinitions.Count) return;
            var lastRow = parent.RowDefinitions[rowIndex + 1];
            height = lastRow.Height;
        }
    
        void HideableGridSplitter_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            Grid parent = base.Parent as Grid;
            if (parent == null) return;
    
            int rowIndex = Grid.GetRow(this);
    
            if (rowIndex + 1 >= parent.RowDefinitions.Count) return;
    
            var lastRow = parent.RowDefinitions[rowIndex + 1];
    
            if (this.Visibility == Visibility.Visible)
            {
                lastRow.Height = height;
            }
            else
            {
                height = lastRow.Height; 
                lastRow.Height = new GridLength(0);
            }
    
        }