2015-10-07 92 views
0

我想要做的是基于复选框切换折叠WPF UI的底部部分。迄今为止,这大多按预期工作。在您逐步浏览图片时,您会看到一旦网格分离器被移动,折叠就停止工作。我不明白为什么或如何解决这个问题。wpf切换可见性崩溃只能工作一次

应用程序的开始显示正确。

Initial opening of the application

切换复选框和botttom部分消失预期。

enter image description here

切换复选框一次,然后移动分割垂直,出现预期的一切。

enter image description here

现在切换复选框,最后一次,你会发现顶部部分不填写申请喜欢它曾经之前。这是它破裂的地方!我希望黄色部分可以像在初始切换中那样填充UI。

enter image description here

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

回答

2

之所以这个幸福ens是,当你移动分离器时,它会覆盖最后RowDefinitionHeight属性,并将它设置为Grid的相应行中出现的任何实际高度 - 第二个StackPanel(底部)。它不再设置为Auto,因此即使折叠底部部分,该行也会保持其高度 - 因此是空的空间。

我有时会发现自己处于类似的情况,我所做的是跨越控制器,我想占用所有空间,使用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类派生,并把你自己的知名度逻辑。这里有一个例子:

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

然后使用类,而不是在网格RowDefinitionIsVisible属性绑定到复选框的选中状态。

+0

会有一种方法来重置Grid.Row高度是最大的可以而不是rowspan? – JokerMartini

+0

您可以使用样式来设置'RowDefinition.Height'属性,并在复选框未选中时使用类似的触发器将其设置为'0',但它看起来像分隔符使用本地值设置高度,该值位于设置的值之前风格,所以它会“打破”反正。请参见[依赖属性值优先级](https://msdn.microsoft.com/en-us/library/vstudio/ms743230(v = vs.100).aspx)。 – Grx70

+0

是的,我实际上只是试图,它不工作。似乎是一个合理的解决方案,但突破 – JokerMartini

0

它看起来像StackPanelGridSplitter都塌了,但Grid.Row 3不是。我不确定为什么自动高度没有关闭它。编辑:我看到@ Grx70已经解释它。

此:Hide grid row in WPF 表明,所有儿童设置为Visibility.Collapsed应该工作,但你必须Grid.Row 3的高度设置为0

的选项,我觉得身高=“5”的你GridSplitter可能会保留占用空间,优先于样式设置(它被折叠并从中获得高度0,但从高度=“5”获得高度5,这会获胜(但它仍然是不可见的)。更好,但在风格上也是如此:

<Setter Property="Height" Value="5" />