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>

看起来 StackPanelGridSplitter 折叠了,但 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" />

发生这种情况的原因是,当您移动拆分器时,它会覆盖最后一个 RowDefinitionHeight 属性 并将其设置为实际高度根据 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 属性 绑定到复选框的选中状态。