GridSplitter 移动后使用 Expander 调整网格大小不起作用

Resizing Grid with Expander not working after GridSplitter moved

背景

我正在尝试创建一个控件,顶部是文件资源管理器,底部是 TreeView,中间用 GridSplitter 分隔。用户可以更改文件资源管理器的大小,但不能超过最小值。当 Expander 折叠时,TreeView 获得所有空间。 Expander 展开后会恢复到折叠前的大小。

例子

使用 post 我试着做了一个工作示例。

<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>

当我折叠并展开 GridSplitter 时,调整大小首先起作用。

问题 1

移动GridSplitter后,折叠后调整大小不再起作用。

问题2

我可以调整大小超过 MinHeight 的 150,我放在 Expander 行的 RowDefinition 中。

如何解决这些问题?

有几个原因导致您当前的 XAML 不起作用。

  1. 您的 MinHeight 设置在嵌套在 GridSplitter 看不到的面板内的元素上。所以它永远不会遵守尺寸。
  2. GridSplitter 会覆盖其相邻 RowDefinition 的高度 属性,因此,您无法使用样式触发器来操纵高度,以便在扩展器展开和折叠时动态调整大小
  3. 没有简单的方法可以在 Expander 折叠并再次展开时恢复 RowDefinition 之前的高度。

这是一个工作示例,我在其中重组了您的 XAML 以便 GridSplitter 可以服从您的 Expander 的 MinHeight。

我还介绍了一个简单的附加行为 class,它将对 Expander 的 Expanded 和 Collapsed 事件做出反应,并将适当的目标 RowDefinition 的高度设置为 Auto,以便您获得所需的自动调整大小。

附加行为 class 还会保留目标 RowDefinition 的先前高度,并将在扩展器展开时恢复它。

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;
        }
    }
}