在WPF中隐藏网格行

120

我有一个简单的WPF表单,其中在表单上声明了一个Grid。这个Grid有很多行:

<Grid.RowDefinitions>
    <RowDefinition Height="Auto" MinHeight="30" />
    <RowDefinition Height="Auto" Name="rowToHide" />
    <RowDefinition Height="Auto" MinHeight="30" />
</Grid.RowDefinitions>

当我检测到不需要使用某些输入字段时,我希望隐藏名为rowToHide的行。将该行中所有项设置为Visibility = Hidden很容易,但是该行仍然占用Grid中的空间。我尝试将项目的Height = 0进行设置,但似乎没有起作用。

你可以这样想:你有一个表单,在里面有一个下拉菜单,称为“付款类型”,如果人们选择了“现金”,则要隐藏包含银行卡详细信息的行。不能在表单开始时就隐藏这个选项。


请注意以下提示:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/74b72fb6-d89e-4d42-a3b4-c388fc79e218/ - Domokun
8个回答

106

行没有可见性属性,因此像其他人所说的那样,您需要设置高度。另一个选项是使用转换器,以防您在许多视图中需要此功能:

    [ValueConversion(typeof(bool), typeof(GridLength))]
    public class BoolToGridRowHeightConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((bool)value == true) ? new GridLength(1, GridUnitType.Star) : new GridLength(0);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {    // Don't need any convert back
            return null;
        }
    }

然后在适当的视图中 <Grid.RowDefinition> 中:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>

12
UpVoted - 转换器允许将所有内容在Xaml中以声明方式表示。我通常不喜欢使用代码后台来操作视觉效果。 - Allen
1
这非常有用,而且很容易扩展。我建议将其命名为 BoolToGridLengthConverter 并添加一个 VisibleLength 属性,在 (bool)value == true 上返回。这样您也可以将其与 Auto 和任何固定值一起重复使用。 - LuckyLikey
2
很好的答案。我想你是指IsDisplayedRow,而不是IsHiddenRow。 - NielW
我认为如果 ConvertBack 方法没有返回任何内容,你应该返回 DependencyProperty.UnsetValue 而不是 null - StayOnTarget

96

折叠行或列的最佳清晰解决方案是使用DataTrigger。因此,在您的情况下:

<Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" MinHeight="30" />
      <RowDefinition Name="rowToHide">
        <RowDefinition.Style>
          <Style TargetType="{x:Type RowDefinition}">
            <Setter Property="Height" Value="Auto" />
            <Style.Triggers>
              <DataTrigger Binding="{Binding SomeBoolProperty}" Value="True">
                <Setter Property="Height" Value="0" />
              </DataTrigger>
            </Style.Triggers>
          </Style>
        </RowDefinition.Style>
      </RowDefinition>
      <RowDefinition Height="Auto" MinHeight="30" />
    </Grid.RowDefinitions>
  </Grid>

7
我喜欢这种方法,因为您不需要额外添加C#代码。 - user11909
2
不要忘记在代码后台实现INotifyPropertyChanged,以便在更改SomeBoolProperty时它能够正常工作 :)。 - benichka

55
你也可以通过引用网格中的行,然后更改行本身的高度来实现这一点。
XAML
<Grid Grid.Column="2" Grid.Row="1" x:Name="Links">
   <Grid.RowDefinitions>
      <RowDefinition Height="60" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" />
      <RowDefinition Height="80" />
   </Grid.RowDefinitions>
</Grid>

VB.NET

If LinksList.Items.Count > 0 Then
   Links.RowDefinitions(2).Height = New GridLength(1, GridUnitType.Star)
Else
   Links.RowDefinitions(2).Height = New GridLength(0)
End If

虽然网格内元素的折叠也可以实现,但如果您的网格中有许多没有可折叠的包含元素的项目,则这种方法会更简单。这将提供一个很好的替代方案。


2
这也有一个优点,就是可以与使用星号符号的行一起工作! - Johny Skovdal
1
在代码中执行此操作是最清晰、最易读的解决方案。也许可以在“RowDefinition”之后添加一个注释,如 <RowDefinition Height="*" /><!-- 通过代码设置高度 --> - Kay Zed
2
我认为这不是最清晰和可读性最高的解决方案,因为功能代码分为两个独立的文件。实际上,所有这些都可以通过纯XAML完成-请参阅我的答案。 - Lukáš Koten
我的需求有些不同,而且是C#语言的,但这个例子指引了我正确的方向。谢谢! - nrod

33

参考资料:Visibility 是一个三态的 System.Windows.Visibility 枚举类型:

  • Visible - 元素被渲染并参与布局。
  • Collapsed - 元素不可见,不参与布局。实际上它的高度和宽度都为0,就像不存在一样。
  • Hidden - 元素不可见但继续参与布局。

请参阅此提示WPF Tips and Tricks线程中的其他提示。


1
将行中的所有项设置为Visibility.Collapsed已经生效了,谢谢。 - Richard
1
我给这个回答点了踩,因为我认为@TravisPUK的回答包含了一个更清晰、更明显的解决方案。 - testpattern
13
通常使用downvote来指出错误的答案。如果其他答案更好,只需upvote即可。 - Metro Smurf
7
@MetroSmurf,说得好。可以认为你的答案不正确,因为RowDefinition没有Visibility属性。TravisPUK展示了如何隐藏行,这应该是被接受的答案。 - testpattern

10

您可以将行中的控件(字段)的Visibility属性设置为“Collapsed”,而不是调整网格行。这将确保控件不占用任何空间,并且如果您的Grid Row Height =“Auto”,则该行将隐藏,因为行中的所有控件都具有Visibility =“Collapsed”。

<Grid>
       <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition Height="Auto" Name="rowToHide" />
       </Grid.RowDefinitions>

   <Button Grid.Row=0 Content="Click Me" Height="20">
       <TextBlock Grid.Row=1 
Visibility="{Binding Converter={StaticResource customVisibilityConverter}}" Name="controlToHide"/>

</Grid>

使用这种方法更好,因为控件的可见性可以通过转换器绑定到某个属性上。


9

只需要这样做:
rowToHide.Height = new GridLength(0);

如果您使用visibility.Collapse,则必须为该行的每个成员设置它。


7

我有一个类似的想法,通过继承RowDefinition来实现(仅供参考)

public class MyRowDefinition : RowDefinition
{
    private GridLength _height;

    public bool IsHidden
    {
        get { return (bool)GetValue(IsHiddenProperty); }
        set { SetValue(IsHiddenProperty, value); }
    }

    // Using a DependencyProperty as the backing store for IsHidden.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsHiddenProperty =
        DependencyProperty.Register("IsHidden", typeof(bool), typeof(MyRowDefinition), new PropertyMetadata(false, Changed));

    public static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var o = d as MyRowDefinition;
        o.Toggle((bool)e.NewValue);
    }

    public void Toggle(bool isHidden)
    {
        if (isHidden)
        {
            _height = this.Height;
            this.Height = new GridLength(0, GridUnitType.Star);
        }                                                     
        else
            this.Height = _height;
    }          
}

现在你可以按照以下方式使用它:
 <Grid.RowDefinitions>
        <RowDefinition Height="2*" />
        <my:MyRowDefinition Height="4*" IsHidden="false" x:Name="RowToHide" />
        <RowDefinition Height="*" />
        <RowDefinition Height="60" />
    </Grid.RowDefinitions>

并切换到

RowToHide.IsHidden = !RowToHide.IsHidden;

7
将行的内容可见性设置为Visibility.Collapsed而不是Hidden。这将使内容停止占用空间,行将适当缩小。

1
我在其他地方看到有人提到了行可见性。但是行没有可见状态?将行中的所有项设置为Visibility.Collapsed可以起作用。 - Richard
5
@Richard: 你无法设置RowDefinition.Visibility,因为它不是UIElement类型 - 但是你可以将该行(或该行中的每列)所有内容放入一个单独的容器中,并设置该容器的可见性。请注意,此操作不改变原始意思。 - Reed Copsey
1
如果您的网格行没有任何内容,但有固定的高度,那么有没有方便的方法来显示/隐藏呢? - kevinarpe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接