Masquer la ligne de la grille dans WPF

94

J'ai un formulaire WPF simple avec un Griddéclaré sur le formulaire. Cela Grida un tas de lignes:

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

La ligne nommée rowToHidecontient quelques champs d'entrée et je veux masquer cette ligne après avoir détecté que je n'ai pas besoin de ces champs. Il est assez simple de définir uniquement Visibility = Hiddentous les éléments de la ligne, mais la ligne occupe toujours de l'espace dans le fichier Grid. J'ai essayé de régler Height = 0les éléments, mais cela n'a pas semblé fonctionner.

Vous pouvez y penser comme ceci: vous avez un formulaire, vous y trouverez une liste déroulante indiquant "Type de paiement", et si la personne sélectionne "Espèces", vous voulez masquer la ligne contenant les détails de la carte. Ce n'est pas une option pour démarrer le formulaire avec ce caché déjà.

Richard
la source
1
voir cette astuce sur la visibilité étant un système à 3 états (dans le fil de discussion WPF): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/…
Metro Smurf
Des trucs géniaux ... Si vous le notiez comme réponse, je marquerais cela ...
Richard
Jetez également un œil à cette astuce: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
Domokun

Réponses:

88

La ligne n'a pas de propriété Visibility, donc comme d'autres l'ont dit, vous devez définir la hauteur. Une autre option consiste à utiliser un convertisseur, au cas où vous auriez besoin de cette fonctionnalité dans de nombreuses vues:

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

Et puis dans la vue appropriée <Grid.RowDefinition>:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>
Modèle de test
la source
10
UpVoted - Les convertisseurs permettent à tout cela d'être déclaratif en Xaml. Je déteste généralement utiliser le code-behind pour jouer avec des éléments visuels.
Allen
1
Ceci est très utile et peut facilement être étendu. Je suggère de l'appeler BoolToGridLengthConverteret d'ajouter un VisibleLength-Property, pour revenir (bool)value == true. C'est ainsi que vous pouvez également le réutiliser avec Auton'importe quelle valeur de correction.
LuckyLikey
1
Très bonne réponse. Je suppose que vous vouliez dire IsDisplayedRow, pas IsHiddenRow.
NielW
72

La meilleure et propre solution pour réduire les lignes ou les colonnes est d'utiliser un DataTrigger donc dans votre cas:

<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
la source
5
J'aime cette approche car vous n'avez pas besoin de code C # supplémentaire.
user11909
1
N'oubliez pas de l'implémenter INotifyPropertyChangeddans votre code pour qu'il fonctionne quand il SomeBoolPropertyest modifié :).
benichka
55

Vous pouvez également le faire en référençant la ligne dans la grille, puis en modifiant la hauteur de la ligne elle-même.

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

Bien que la réduction des éléments dans la grille fonctionne également, c'est un peu plus simple si vous avez de nombreux éléments dans la grille qui ne comportent pas d'élément englobant pouvant être réduit. Cela constituerait une bonne alternative.

TravisPUK
la source
2
Cela a également l'avantage de travailler avec des lignes qui utilisent la notation en étoile!
Johny Skovdal
1
Faire cela dans le code est la solution la plus claire et la plus lisible. Peut-être ajouter un commentaire après le RowDefinition, comme<RowDefinition Height="*" /><!-- Height set in code behind -->
Kay Zed
2
Je ne pense pas que ce soit la solution la plus claire et la plus lisible puisque le code fonctionnel est divisé en deux fichiers séparés. En fait, tout peut être fait avec du XAML pur - voir ma réponse.
Lukáš Koten
Mes besoins étaient un peu différents et en C # mais cet exemple m'a orienté dans la bonne direction. Merci!
nrod le
30

Pour référence, Visibilityest une énumération System.Windows.Visibility à trois états :

  • Visible - L'élément est rendu et participe à la mise en page.
  • Réduit: l'élément est invisible et ne participe pas à la mise en page. En lui donnant effectivement une hauteur et une largeur de 0 et se comportant comme s'il n'existait pas.
  • Caché - L'élément est invisible mais continue de participer à la mise en page.

Consultez cette astuce et d'autres astuces sur le fil WPF Tips and Tricks .

Schtroumpf du métro
la source
1
La définition de tous les éléments de la ligne sur Visibility.Collapsed a fonctionné, merci.
Richard
1
J'ai rejeté cela parce que je pense que la réponse de @ TravisPUK contient une solution plus claire et plus évidente.
testpattern
11
@testpattern - les votes négatifs sont généralement utilisés pour les réponses incorrectes. Si l'autre réponse est meilleure, votez simplement.
Metro Schtroumpf
6
@MetroSmurf assez juste. On peut soutenir que votre réponse n'est pas correcte car RowDefinition n'a pas de propriété pour la visibilité. TravisPUK montre comment masquer une ligne et cela devrait être la réponse acceptée.
testpattern
8

Au lieu de jouer avec la ligne de grille, vous pouvez définir la propriété Visibility des contrôles (champs de la ligne) sur "Réduit". Cela garantira que les contrôles ne prennent pas d'espace et si vous avez Grid Row Height = "Auto", alors la ligne sera masquée car tous les contrôles de la ligne ont 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>

Cette méthode est meilleure car la visibilité des contrôles peut être liée à une propriété à l'aide d'un convertisseur.

user3726565
la source
7

Faites simplement ceci:
rowToHide.Height = new GridLength(0);

si vous utilisez, visibility.Collapsevous devez le définir pour chaque membre de la ligne.

NOM D'UTILISATEUR
la source
6

Définissez la visibilité du contenu de la ligne sur au Visibility.Collapsedlieu de Caché. Cela empêchera le contenu de prendre de l'espace et la ligne se réduira de manière appropriée.

Reed Copsey
la source
1
J'ai vu ailleurs quelqu'un a mentionné la visibilité des lignes. Mais le Row n'a pas d'état de visibilité? La définition de tous les éléments de la ligne sur la visibilité.
Richard
5
@Richard: Vous ne pouvez pas définir RowDefinition.Visibility car ce n'est pas un UIElement - mais vous pouvez placer tout votre contenu pour la ligne (ou chaque colonne de la ligne) dans un seul conteneur et définir la visibilité de ce conteneur.
Reed Copsey
1
Que faire si votre ligne de grille n'a pas de contenu, mais une hauteur fixe? Existe-t-il un moyen pratique d'afficher / de masquer?
kevinarpe
4

J'ai eu une idée similaire en héritant de RowDefinition (juste pour l'intérêt)

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

Vous pouvez maintenant l'utiliser comme suit:

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

et basculer avec

RowToHide.IsHidden = !RowToHide.IsHidden;
Mat
la source