首页 > 解决方案 > GridSplitter 移动后使用 Expander 调整网格大小不起作用

问题描述

背景

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

背景

例子

使用这篇文章,我尝试制作一个工作示例。

<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,折叠后调整大小不再起作用。 问题 1

问题 2

我可以调整超出MinHeight我放在行中的 150 的RowDefinition大小Expander问题 2

如何解决这些问题?

标签: wpfxamlexpandergridsplitter

解决方案


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

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

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

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

附加的行为类还保留目标 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;
        }
    }
}

推荐阅读