118

I have a simple WPF form with a Grid declared on the form. This Grid has a bunch of rows:

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

The row named rowToHide contains a few input fields and I want to hide this row after I detect I don't need these fields. It's simple enough to just set Visibility = Hidden to all items in the row, but the row still takes up space in the Grid. I tried setting Height = 0 to the items, but that didn't seem to work.

You can think of it like this: You have a form, in there you have a drop down saying "Payment Type", and if the person selects "Cash", you want to hide the row containing the Card details. It isn't an option to start the form with this hidden already.

Palec
  • 12,743
  • 8
  • 69
  • 138
Richard
  • 3,207
  • 5
  • 30
  • 35
  • Have a look at this tip as well: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/74b72fb6-d89e-4d42-a3b4-c388fc79e218/ – Domokun Feb 03 '11 at 01:49

8 Answers8

105

Row does not have a Visibility property, so as others have said, you need to set the Height. Another option is to use a converter, in case you need this functionality in many views:

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

And then in the appropriate view <Grid.RowDefinition>:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>
testpattern
  • 2,382
  • 1
  • 25
  • 29
  • 12
    UpVoted - Converters permit all this to be declarative in Xaml. I generally hate using code-behind to fiddle with visual stuff. – Allen May 22 '14 at 13:43
  • 1
    This is pretty useful and can easily be extended. I suggest calling it `BoolToGridLengthConverter` and adding a `VisibleLength`-Property, to return on `(bool)value == true`. Thats how you can also reuse it with `Auto` and any fix-Value. – LuckyLikey Jul 19 '17 at 09:35
  • 2
    Great answer. I assume you meant IsDisplayedRow, not IsHiddenRow. – NielW May 30 '18 at 22:46
  • I believe that if `ConvertBack` doesn't return anything you are supposed to return `DependencyProperty.UnsetValue`, not `null`. – StayOnTarget Jul 20 '22 at 12:46
96

The best and clean solution to collapse rows or columns is to use a DataTrigger so in your case:

<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>
Lukáš Koten
  • 1,191
  • 10
  • 22
55

You can also do this by referencing the Row in the Grid and then changing the Height of the row itself.

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

Whilst the Collapsing of the elements within the Grid also works, this is a bit simpler if you have many items in the Grid that does not have an enclosing element that can be collapsed. This would provide a good alternative.

TravisPUK
  • 1,043
  • 1
  • 14
  • 17
  • 2
    This also has the advantage of working with rows that uses the star notation! – Johny Skovdal Sep 06 '12 at 06:58
  • 1
    Doing this in code is the clearest, most readable solution. Perhaps add a comment after the `RowDefinition`, like `` – Kay Zed Mar 25 '16 at 04:50
  • 2
    I don't think this is the clearest and most readable solution since the functional code is divided into two separated files. In fact it all can be done with pure XAML - see my answer. – Lukáš Koten Jun 12 '18 at 17:36
  • My needs were a bit different and in C# but this example pointed me in the right direction. Thanks! – nrod Apr 14 '20 at 15:04
33

For reference, Visibility is a three-state System.Windows.Visibility enumeration:

  • Visible - The element gets rendered and participates in layout.
  • Collapsed - The element is invisible and does not participate in layout. Effectively giving it a height and width of 0 and behaving as if it doesn't exist.
  • Hidden - The element is invisible but continues to participate in layout.

See this tip and other tips on the WPF Tips and Tricks thread.

Community
  • 1
  • 1
Metro Smurf
  • 37,266
  • 20
  • 108
  • 140
  • 1
    Setting all the Items in the Row to Visibility.Collapsed worked, thanks. – Richard Mar 25 '10 at 15:33
  • 1
    I downvoted this because I think @TravisPUK's answer contains a clearer, more obvious solution. – testpattern Feb 19 '14 at 14:48
  • 13
    @testpattern - downvotes are typically used for incorrect answers. If the other answer is better, just upvote it. – Metro Smurf Feb 19 '14 at 17:39
  • 7
    @MetroSmurf fair enough. Arguably, your answer is not correct because RowDefinition does not have a property for Visibility. TravisPUK shows how to hide a row and that should be the accepted answer. – testpattern Feb 20 '14 at 09:54
10

Instead of fiddling with the Grid Row, you can set the Visibility property of the Controls (fields in the row) to "Collapsed". This will ensure that the controls don't take up any space and if you have Grid Row Height="Auto", then the row will be hidden as all the controls in the row have 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>

This method is better because the Visibility of the controls can be bound to some property with the help of a Converter.

user3726565
  • 101
  • 1
  • 3
8

Simply do this:
rowToHide.Height = new GridLength(0);

if u will use visibility.Collapse then u have to set it for every member of the row.

USER_NAME
  • 1,029
  • 1
  • 14
  • 33
7

Set the Row's content visibility to Visibility.Collapsed instead of Hidden. This will make the content stop taking up space, and the row will shrink appropriately.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 1
    I've seen somewhere else someone mentioned the Row Visibility. But the Row doesn't have a visibility state? Setting all the Items in the Row to Visibility.Collapsed worked though. – Richard Mar 23 '10 at 17:47
  • 5
    @Richard: You can't set RowDefinition.Visibility since it's not a UIElement - but you can put all of your content for the row (or each column within the row) into a single container, and set that container's visibilty. – Reed Copsey Mar 23 '10 at 17:51
  • 1
    What if your grid row does not have any content, but a fixed height? Is there a convenient way to show/hide? – kevinarpe Dec 12 '12 at 10:53
7

I had a similar idea by inheriting RowDefinition (just for interest)

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

Now you can use it as following:

 <Grid.RowDefinitions>
        <RowDefinition Height="2*" />
        <my:MyRowDefinition Height="4*" IsHidden="false" x:Name="RowToHide" />
        <RowDefinition Height="*" />
        <RowDefinition Height="60" />
    </Grid.RowDefinitions>

and toggle with

RowToHide.IsHidden = !RowToHide.IsHidden;
Matt
  • 4,612
  • 1
  • 24
  • 44