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 不起作用。
- 您的 MinHeight 设置在嵌套在 GridSplitter 看不到的面板内的元素上。所以它永远不会遵守尺寸。
- GridSplitter 会覆盖其相邻 RowDefinition 的高度 属性,因此,您无法使用样式触发器来操纵高度,以便在扩展器展开和折叠时动态调整大小
- 没有简单的方法可以在 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;
}
}
}
背景
我正在尝试创建一个控件,顶部是文件资源管理器,底部是 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
后,折叠后调整大小不再起作用。
问题2
我可以调整大小超过 MinHeight
的 150,我放在 Expander
行的 RowDefinition
中。
如何解决这些问题?
有几个原因导致您当前的 XAML 不起作用。
- 您的 MinHeight 设置在嵌套在 GridSplitter 看不到的面板内的元素上。所以它永远不会遵守尺寸。
- GridSplitter 会覆盖其相邻 RowDefinition 的高度 属性,因此,您无法使用样式触发器来操纵高度,以便在扩展器展开和折叠时动态调整大小
- 没有简单的方法可以在 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;
}
}
}