Ocultar fila de cuadrícula en WPF

94

Tengo un formulario WPF simple con un Griddeclarado en el formulario. Esto Gridtiene un montón de filas:

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

La fila nombrada rowToHidecontiene algunos campos de entrada y quiero ocultar esta fila después de detectar que no necesito estos campos. Es bastante simple configurar Visibility = Hiddentodos los elementos de la fila, pero la fila aún ocupa espacio en el Grid. Intenté configurar Height = 0los elementos, pero no pareció funcionar.

Puede pensarlo así: tiene un formulario, allí tiene un menú desplegable que dice "Tipo de pago", y si la persona selecciona "Efectivo", desea ocultar la fila que contiene los detalles de la Tarjeta. No es una opción comenzar el formulario con esto ya oculto.

Ricardo
fuente
1
vea este consejo sobre la visibilidad como un sistema de 3 estados (en el hilo de consejos de WPF): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/…
Metro Smurf
Cosas brillantes ... Si lo pusieras como respuesta, lo marcaría ...
Richard
Eche un vistazo a este consejo también: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
Domokun

Respuestas:

88

Row no tiene una propiedad de Visibilidad, por lo que, como han dicho otros, debe establecer la Altura. Otra opción es utilizar un convertidor, en caso de que necesite esta funcionalidad en muchas vistas:

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

Y luego en la vista apropiada <Grid.RowDefinition>:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>
patrón de prueba
fuente
10
UpVoted: los convertidores permiten que todo esto sea declarativo en Xaml. En general, odio usar código subyacente para jugar con cosas visuales.
Allen
1
Esto es bastante útil y se puede ampliar fácilmente. Sugiero llamarlo BoolToGridLengthConvertery agregar una VisibleLength-Property, para regresar (bool)value == true. Así es como también puede reutilizarlo con Autocualquier valor fijo.
LuckyLikey
1
Gran respuesta. Supongo que te refieres a IsDisplayedRow, no a IsHiddenRow.
NielW
72

La mejor y más limpia solución para contraer filas o columnas es usar un DataTrigger, en su caso:

<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
fuente
5
Me gusta este enfoque porque no necesita código C # adicional.
user11909
1
No olvide implementar INotifyPropertyChangeden su código para que funcione cuando SomeBoolPropertyse cambie :).
benichka
55

También puede hacer esto haciendo referencia a la fila en la cuadrícula y luego cambiando la altura de la fila.

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

Si bien el colapso de los elementos dentro de la cuadrícula también funciona, esto es un poco más simple si tiene muchos elementos en la cuadrícula que no tienen un elemento adjunto que pueda colapsarse. Esto proporcionaría una buena alternativa.

TravisPUK
fuente
2
¡Esto también tiene la ventaja de trabajar con filas que usan la notación de estrella!
Johny Skovdal
1
Hacer esto en código es la solución más clara y legible. Quizás agregue un comentario después del RowDefinition, como<RowDefinition Height="*" /><!-- Height set in code behind -->
Kay Zed
2
No creo que esta sea la solución más clara y legible, ya que el código funcional está dividido en dos archivos separados. De hecho, todo se puede hacer con XAML puro; vea mi respuesta.
Lukáš Koten
Mis necesidades eran un poco diferentes y estaban en C #, pero este ejemplo me indicó la dirección correcta. ¡Gracias!
nrod
30

Como referencia, Visibilityes una enumeración System.Windows.Visibility de tres estados :

  • Visible: el elemento se renderiza y participa en el diseño.
  • Colapsado: el elemento es invisible y no participa en el diseño. Dándole efectivamente una altura y ancho de 0 y comportándose como si no existiera.
  • Oculto: el elemento es invisible pero sigue participando en el diseño.

Vea esta sugerencia y otras sugerencias en el hilo de sugerencias y trucos de WPF .

Pitufo Metro
fuente
1
Establecer todos los elementos de la fila en Visibilidad. Colapsado funcionó, gracias.
Richard
1
Rechacé esto porque creo que la respuesta de @ TravisPUK contiene una solución más clara y obvia.
patrón de prueba
11
@testpattern: los votos negativos se utilizan normalmente para respuestas incorrectas. Si la otra respuesta es mejor, simplemente vota a favor.
Metro Smurf
6
@MetroSmurf bastante justo. Podría decirse que su respuesta no es correcta porque RowDefinition no tiene una propiedad para Visibilidad. TravisPUK muestra cómo ocultar una fila y esa debería ser la respuesta aceptada.
patrón de prueba
8

En lugar de jugar con la fila de la cuadrícula, puede establecer la propiedad Visibilidad de los controles (campos en la fila) en "Contraído". Esto asegurará que los controles no ocupen ningún espacio y si tiene Grid Row Height = "Auto", entonces la fila se ocultará ya que todos los controles en la fila tienen 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>

Este método es mejor porque la visibilidad de los controles se puede vincular a alguna propiedad con la ayuda de un convertidor.

usuario3726565
fuente
7

Simplemente haz esto:
rowToHide.Height = new GridLength(0);

si va a usar, visibility.Collapseentonces debe configurarlo para cada miembro de la fila.

USER_NAME
fuente
6

Establezca la visibilidad del contenido de la fila en Visibility.Collapsedlugar de Oculto. Esto hará que el contenido deje de ocupar espacio y la fila se reducirá adecuadamente.

Reed Copsey
fuente
1
He visto en otro lugar que alguien mencionó la visibilidad de fila. ¿Pero el Row no tiene un estado de visibilidad? Establecer todos los elementos de la fila en Visibilidad, aunque colapsó funcionó.
Richard
5
@Richard: No puede establecer RowDefinition.Visibility ya que no es un UIElement, pero puede poner todo su contenido para la fila (o cada columna dentro de la fila) en un solo contenedor y establecer la visibilidad de ese contenedor.
Reed Copsey
1
¿Qué pasa si su fila de cuadrícula no tiene ningún contenido, sino una altura fija? ¿Existe una forma conveniente de mostrar / ocultar?
kevinarpe
4

Tuve una idea similar al heredar RowDefinition (solo por interés)

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

Ahora puede usarlo de la siguiente manera:

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

y alternar con

RowToHide.IsHidden = !RowToHide.IsHidden;
Mate
fuente