wpf 切换可见性折叠只工作一次
wpf toggling visibility collapse only works once
我想要做的是根据复选框切换折叠 WPF ui 的底部部分。到目前为止,这大部分都按预期工作。在您逐步浏览图像时,您会看到在网格分离器移动后折叠停止工作。我不明白为什么或如何解决这个问题。
应用程序启动,显示正确。
切换复选框,底部部分会按预期消失。
再次勾选复选框,然后垂直移动拆分器,一切都按预期显示。
现在最后一次勾选复选框,您会发现顶部部分不再像以前那样填充应用程序。这就是它看起来破损的地方!我希望黄色部分像在初始切换中那样填充 UI 。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="250" Width="525"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<CheckBox Name="ToggleVisibility" Margin="10" IsChecked="True" Content="Toggle Bottom Section"></CheckBox>
<StackPanel Background="#feca00" Grid.Row="1">
<TextBlock FontSize="20" Foreground="#58290A">Top Section</TextBlock>
</StackPanel>
<GridSplitter Grid.Row="2" Height="5" HorizontalAlignment="Stretch">
<GridSplitter.Style>
<Style TargetType="GridSplitter">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ToggleVisibility, Path=IsChecked}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
</GridSplitter>
<StackPanel Grid.Row="3" Background="LightBlue">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ToggleVisibility, Path=IsChecked}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock FontSize="20" Foreground="black">Bottom Section</TextBlock>
</StackPanel>
</Grid>
</Window>
看起来 StackPanel
和 GridSplitter
折叠了,但 Grid.Row
3 没有折叠。我不确定为什么自动高度没有关闭它。编辑:我看到@Grx70 已经解释过了。
这个:Hide grid row in WPF
建议将所有子项设置为 Visibility.Collapsed
应该可行,但您可以选择将 Grid.Row 3 的高度设置为 0.
我认为您的 GridSplitter
的 Height="5" 也可能会占用 space,优先于样式设置(它被折叠并从中获得高度 0,但是从 Height="5" 获得高度 5,它获胜(但它仍然是不可见的)。这可能更好,但在样式中也是如此:
<Setter Property="Height" Value="5" />
发生这种情况的原因是,当您移动拆分器时,它会覆盖最后一个 RowDefinition
的 Height
属性 并将其设置为实际高度根据 Grid
的行 - 您的情况下的第二个 StackPanel
(底部)。它不再设置为 Auto
,因此即使您折叠底部部分,该行仍保持其高度 - 因此空 space.
我有时发现自己处于类似的情况,然后我所做的就是跨越控件,我想占据所有 space,使用附加的 Grid.RowSpan
跨越剩余的行属性。在您的情况下,您可以通过将以下样式应用于您的第一个 StackPanel
(顶部部分)来实现它:
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=ToggleVisibility}" Value="False">
<Setter Property="Grid.RowSpan" Value="3" />
</DataTrigger>
</Style.Triggers>
</Style>
那么 StackPanel
将跨越到 Grid
的底部,而不管后续行的高度如何。
编辑
由于您对跨越控件不满意,这里有另一个解决方案:派生自 RowDefinition
class 并连接您自己的可见性逻辑。这是一个例子:
public class MyRowDefinition : RowDefinition
{
static MyRowDefinition()
{
HeightProperty.OverrideMetadata(
typeof(MyRowDefinition),
new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceHeightPropertyValue
});
}
private static object CoerceHeightPropertyValue(DependencyObject d, object baseValue)
{
if (Equals(d.GetValue(IsVisibleProperty), false))
return new GridLength(0d);
else
return baseValue;
}
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
set { SetValue(IsVisibleProperty, value); }
}
public static readonly DependencyProperty IsVisibleProperty =
DependencyProperty.Register(
"IsVisible",
typeof(bool),
typeof(MyRowDefinition),
new FrameworkPropertyMetadata
{
DefaultValue = true,
PropertyChangedCallback = IsVisiblePropertyChanged
});
private static void IsVisiblePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.InvalidateProperty(RowDefinition.HeightProperty);
}
}
然后在您的网格中使用 class 而不是 RowDefinition
并将 IsVisible
属性 绑定到复选框的选中状态。
我想要做的是根据复选框切换折叠 WPF ui 的底部部分。到目前为止,这大部分都按预期工作。在您逐步浏览图像时,您会看到在网格分离器移动后折叠停止工作。我不明白为什么或如何解决这个问题。
应用程序启动,显示正确。
切换复选框,底部部分会按预期消失。
再次勾选复选框,然后垂直移动拆分器,一切都按预期显示。
现在最后一次勾选复选框,您会发现顶部部分不再像以前那样填充应用程序。这就是它看起来破损的地方!我希望黄色部分像在初始切换中那样填充 UI 。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="250" Width="525"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<CheckBox Name="ToggleVisibility" Margin="10" IsChecked="True" Content="Toggle Bottom Section"></CheckBox>
<StackPanel Background="#feca00" Grid.Row="1">
<TextBlock FontSize="20" Foreground="#58290A">Top Section</TextBlock>
</StackPanel>
<GridSplitter Grid.Row="2" Height="5" HorizontalAlignment="Stretch">
<GridSplitter.Style>
<Style TargetType="GridSplitter">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ToggleVisibility, Path=IsChecked}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</GridSplitter.Style>
</GridSplitter>
<StackPanel Grid.Row="3" Background="LightBlue">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Background" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ToggleVisibility, Path=IsChecked}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock FontSize="20" Foreground="black">Bottom Section</TextBlock>
</StackPanel>
</Grid>
</Window>
看起来 StackPanel
和 GridSplitter
折叠了,但 Grid.Row
3 没有折叠。我不确定为什么自动高度没有关闭它。编辑:我看到@Grx70 已经解释过了。
这个:Hide grid row in WPF
建议将所有子项设置为 Visibility.Collapsed
应该可行,但您可以选择将 Grid.Row 3 的高度设置为 0.
我认为您的 GridSplitter
的 Height="5" 也可能会占用 space,优先于样式设置(它被折叠并从中获得高度 0,但是从 Height="5" 获得高度 5,它获胜(但它仍然是不可见的)。这可能更好,但在样式中也是如此:
<Setter Property="Height" Value="5" />
发生这种情况的原因是,当您移动拆分器时,它会覆盖最后一个 RowDefinition
的 Height
属性 并将其设置为实际高度根据 Grid
的行 - 您的情况下的第二个 StackPanel
(底部)。它不再设置为 Auto
,因此即使您折叠底部部分,该行仍保持其高度 - 因此空 space.
我有时发现自己处于类似的情况,然后我所做的就是跨越控件,我想占据所有 space,使用附加的 Grid.RowSpan
跨越剩余的行属性。在您的情况下,您可以通过将以下样式应用于您的第一个 StackPanel
(顶部部分)来实现它:
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=ToggleVisibility}" Value="False">
<Setter Property="Grid.RowSpan" Value="3" />
</DataTrigger>
</Style.Triggers>
</Style>
那么 StackPanel
将跨越到 Grid
的底部,而不管后续行的高度如何。
编辑
由于您对跨越控件不满意,这里有另一个解决方案:派生自 RowDefinition
class 并连接您自己的可见性逻辑。这是一个例子:
public class MyRowDefinition : RowDefinition
{
static MyRowDefinition()
{
HeightProperty.OverrideMetadata(
typeof(MyRowDefinition),
new FrameworkPropertyMetadata
{
CoerceValueCallback = CoerceHeightPropertyValue
});
}
private static object CoerceHeightPropertyValue(DependencyObject d, object baseValue)
{
if (Equals(d.GetValue(IsVisibleProperty), false))
return new GridLength(0d);
else
return baseValue;
}
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
set { SetValue(IsVisibleProperty, value); }
}
public static readonly DependencyProperty IsVisibleProperty =
DependencyProperty.Register(
"IsVisible",
typeof(bool),
typeof(MyRowDefinition),
new FrameworkPropertyMetadata
{
DefaultValue = true,
PropertyChangedCallback = IsVisiblePropertyChanged
});
private static void IsVisiblePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.InvalidateProperty(RowDefinition.HeightProperty);
}
}
然后在您的网格中使用 class 而不是 RowDefinition
并将 IsVisible
属性 绑定到复选框的选中状态。