简体   繁体   中英

Resizing Grid with Expander not working after GridSplitter moved

Background

I'm trying to create a control with a file explorer at the top and TreeView at the bottem separated by a GridSplitter . The user can change the size of the file explorer, but not beyond a minimum value. When the Expander is collapsed, the TreeView gets all the room. When the Expander is expanded it goes back to the size that it was before it collapsed.

背景

Example

Using this post I tried to make a working example.

<Grid Margin="3">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="3*" />
    </Grid.RowDefinitions>

    <Border BorderBrush="Red" BorderThickness="3">
        <Grid Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition>
                    <RowDefinition.Style>
                        <Style TargetType="{x:Type RowDefinition}">
                            <Setter Property="Height" Value="*" />
                            <Setter Property="MinHeight" Value="150" />
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ElementName=MyExpander, Path=IsExpanded}" Value="False">
                                    <Setter Property="Height" Value="24" />
                                    <Setter Property="MinHeight" Value="24" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </RowDefinition.Style>
                </RowDefinition>
            </Grid.RowDefinitions>

            <Button Grid.Row="0" Margin="3" Content="Button 1" HorizontalAlignment="Stretch"/>

            <Expander x:Name="MyExpander" Grid.Row="1" Margin="3" IsExpanded="True">
                <Border BorderBrush="Blue" BorderThickness="3"/>
            </Expander>
        </Grid>
    </Border>

    <GridSplitter
        Grid.Row="1"
        Height="3"
        HorizontalAlignment="Stretch" 
        Margin="3,0,3,0"/>

    <Border Grid.Row="2" BorderBrush="Green" BorderThickness="3"/>  
</Grid>

The resizing works at first when I collapse and expand the GridSplitter .

例子

Problem 1

After the GridSplitter is moved, the resizing after collapse doesn't work anymore. 问题一

Problem 2

I can resize beyond the MinHeight of 150 that I put in the RowDefinition of the Expander row. 问题二

How to solve these problems?

There are a couple reasons why your current XAML doesn't work.

  1. Your MinHeight is set on an element nested inside of a panel that the GridSplitter doesn't see. So it will never honor the size.
  2. The GridSplitter overrides the Height property of its adjacent RowDefinitions and because of this, you cannot use Style Triggers to manipulate the Height in order to get dynamic resizing when your Expander expands and collapses
  3. There is no simple way to restore the previous Height of the RowDefinition when the Expander is collapsed and expanded again.

Here is a working example, where I've restructured your XAML so that the GridSplitter can obey the MinHeight of your Expander.

I've also introduced a simple attached behavior class that will react to the Expander's Expanded and Collapsed events and will set the appropriate target RowDefinition's Height to Auto so that you get the auto resizing that you want.

The attached behavior class also persists the previous Height of the target RowDefinition and will restore it when the expander is expanded.

XAML

<Grid Margin="3">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition x:Name="ExpanderRow">
            <RowDefinition.Style>
                <Style TargetType="{x:Type RowDefinition}">
                    <Setter Property="MinHeight" Value="150" />
                    <Style.Triggers>
                        <DataTrigger
                            Binding="{Binding ElementName=MyExpander, Path=IsExpanded}"
                            Value="False">
                            <Setter Property="MinHeight" Value="40" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </RowDefinition.Style>
        </RowDefinition>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Border
        Grid.Row="0"
        Grid.RowSpan="2"
        BorderBrush="Red"
        BorderThickness="3" />

    <Button
        Grid.Row="0"
        Margin="6"
        HorizontalAlignment="Stretch"
        Content="Button 1" />

    <Expander x:Name="MyExpander"
        Grid.Row="1"
        Margin="6"
        local:ExpanderRowHeightBehavior.IsEnabled="True"
        local:ExpanderRowHeightBehavior.TargetRow="{Binding ElementName=ExpanderRow}"
        IsExpanded="True">
        <Border
            BorderBrush="Blue"
            BorderThickness="3" />
    </Expander>

    <GridSplitter
        Grid.Row="2"
        Height="3"
        Margin="3,0,3,0"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Center" />

    <Border
        Grid.Row="3"
        BorderBrush="Green"
        BorderThickness="3" />
</Grid>

ExpanderRowHeightBehavior.cs

using System.Windows;
using System.Windows.Controls;

namespace SO
{
    public static class ExpanderRowHeightBehavior
    {
        #region IsEnabled (Attached Property)
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached(
                "IsEnabled",
                typeof(bool),
                typeof(ExpanderRowHeightBehavior),
                new PropertyMetadata(false, OnIsEnabledChanged));

        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }

        private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is Expander expander)) return;

            expander.Collapsed += OnCollapsed;
            expander.Expanded += OnExpanded;

        }
        #endregion

        #region TargetRow (Attached Property)
        public static readonly DependencyProperty TargetRowProperty =
            DependencyProperty.RegisterAttached(
                "TargetRow",
                typeof(RowDefinition),
                typeof(ExpanderRowHeightBehavior),
                new PropertyMetadata(null));

        public static RowDefinition GetTargetRow(DependencyObject obj)
        {
            return (RowDefinition)obj.GetValue(TargetRowProperty);
        }

        public static void SetTargetRow(DependencyObject obj, RowDefinition value)
        {
            obj.SetValue(TargetRowProperty, value);
        }
        #endregion

        #region TargetRowPrevHeight (Attached Property)
        public static readonly DependencyProperty TargetRowPrevHeightProperty =
            DependencyProperty.RegisterAttached(
                "TargetRowPrevHeight",
                typeof(GridLength),
                typeof(ExpanderRowHeightBehavior),
                new PropertyMetadata(GridLength.Auto));

        public static GridLength GetTargetRowPrevHeight(DependencyObject obj)
        {
            return (GridLength)obj.GetValue(TargetRowPrevHeightProperty);
        }

        public static void SetTargetRowPrevHeight(DependencyObject obj, GridLength value)
        {
            obj.SetValue(TargetRowPrevHeightProperty, value);
        }
        #endregion

        private static void OnCollapsed(object sender, RoutedEventArgs e)
        {
            if (!(sender is Expander expander)) return;

            var targetRow = GetTargetRow(expander);

            if (targetRow == null) return;

            SetTargetRowPrevHeight(expander, targetRow.Height);

            targetRow.Height = GridLength.Auto;
        }

        private static void OnExpanded(object sender, RoutedEventArgs e)
        {
            if (!(sender is Expander expander)) return;

            var targetRow = GetTargetRow(expander);

            if (targetRow == null) return;

            var targetRowPrevHeight = GetTargetRowPrevHeight(expander);

            targetRow.Height = targetRowPrevHeight;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM