Rasterzeile in WPF ausblenden


94

Ich habe ein einfaches WPF-Formular mit einem Gridauf dem Formular deklarierten. Dies Gridhat eine Reihe von Zeilen:

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

Die genannte Zeile rowToHideenthält einige Eingabefelder. Ich möchte diese Zeile ausblenden, nachdem ich festgestellt habe, dass ich diese Felder nicht benötige. Es ist einfach genug, nur Visibility = Hiddenalle Elemente in der Zeile festzulegen, aber die Zeile nimmt immer noch Platz in der Zeile ein Grid. Ich habe versucht Height = 0, die Elemente einzustellen, aber das schien nicht zu funktionieren.

Sie können sich das so vorstellen: Sie haben ein Formular, in dem sich ein Dropdown-Menü mit der Aufschrift "Zahlungsart" befindet. Wenn die Person "Bargeld" auswählt, möchten Sie die Zeile mit den Kartendetails ausblenden. Es ist keine Option, das Formular mit diesem bereits ausgeblendeten zu starten.


1
Siehe diesen Tipp zu Sichtbarkeit als 3-Zustands-System (im WPF-Tipps-Thread): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/…
Metro Smurf

Geniales Zeug ... Wenn Sie es als Antwort aufschreiben würden, würde ich das markieren ...
Richard

Schauen Sie sich auch diesen Tipp an: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
Domokun

Antworten:


87

Row hat keine Visibility-Eigenschaft. Wie andere bereits gesagt haben, müssen Sie die Höhe festlegen. Eine andere Möglichkeit ist die Verwendung eines Konverters, falls Sie diese Funktionalität in vielen Ansichten benötigen:

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

Und dann in der entsprechenden Ansicht <Grid.RowDefinition>:

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

10
UpVoted - Konverter erlauben, dass all dies in Xaml deklarativ ist. Ich hasse es im Allgemeinen, Code-Behind zu verwenden, um mit visuellen Dingen herumzuspielen.
Allen

1
Dies ist sehr nützlich und kann leicht erweitert werden. Ich schlage vor, es aufzurufen BoolToGridLengthConverterund eine VisibleLengthEigenschaft hinzuzufügen, um fortzufahren (bool)value == true. So können Sie es auch mit Autound jedem Fix-Wert wiederverwenden .
LuckyLikey

1
Gute Antwort. Ich nehme an, Sie meinten IsDisplayedRow, nicht IsHiddenRow.
NielW

72

Die beste und sauberste Lösung zum Reduzieren von Zeilen oder Spalten ist die Verwendung eines DataTriggers. In Ihrem Fall also:

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

5
Ich mag diesen Ansatz, weil Sie keinen zusätzlichen C # -Code benötigen.
user11909

1
Vergessen Sie nicht, INotifyPropertyChangedin Ihren Code dahinter zu implementieren, damit er funktioniert, wenn er SomeBoolPropertygeändert wird :).
Benichka

55

Sie können dies auch tun, indem Sie auf die Zeile im Raster verweisen und dann die Höhe der Zeile selbst ändern.

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

Das Reduzieren der Elemente im Raster funktioniert zwar auch, dies ist jedoch etwas einfacher, wenn Sie viele Elemente im Raster haben, die kein umschließendes Element enthalten, das reduziert werden kann. Dies wäre eine gute Alternative.


2
Dies hat auch den Vorteil, mit Zeilen zu arbeiten, die die Sternnotation verwenden!
Johny Skovdal

1
Dies im Code zu tun, ist die klarste und am besten lesbare Lösung. Vielleicht fügen Sie einen Kommentar nach dem RowDefinition, wie<RowDefinition Height="*" /><!-- Height set in code behind -->
Kay Zed

2
Ich denke nicht, dass dies die klarste und am besten lesbare Lösung ist, da der Funktionscode in zwei getrennte Dateien unterteilt ist. Tatsächlich kann alles mit reinem XAML gemacht werden - siehe meine Antwort.
Lukáš Koten

Meine Bedürfnisse waren etwas anders und in C #, aber dieses Beispiel hat mich in die richtige Richtung gelenkt. Vielen Dank!
14.

30

Als Referenz Visibilitydient eine System.Windows.Visibility- Aufzählung mit drei Zuständen :

  • Sichtbar - Das Element wird gerendert und nimmt am Layout teil.
  • Reduziert - Das Element ist unsichtbar und nimmt nicht am Layout teil. Geben Sie ihm effektiv eine Höhe und Breite von 0 und verhalten Sie sich so, als ob er nicht existiert.
  • Versteckt - Das Element ist unsichtbar, nimmt aber weiterhin am Layout teil.

Siehe diesen Tipp und andere Tipps im WPF- Thread mit Tipps und Tricks .


1
Das Einstellen aller Elemente in der Zeile auf Sichtbarkeit. Zusammengeklappt hat funktioniert, danke.
Richard

1
Ich habe dies abgelehnt, weil ich denke, dass die Antwort von @ TravisPUK eine klarere, offensichtlichere Lösung enthält.
Testmuster

11
@testpattern - Downvotes werden normalerweise für falsche Antworten verwendet. Wenn die andere Antwort besser ist, stimmen Sie sie einfach ab.
Metro Schlumpf

6
@MetroSmurf fair genug. Ihre Antwort ist wahrscheinlich nicht korrekt, da RowDefinition keine Eigenschaft für Sichtbarkeit hat. TravisPUK zeigt, wie eine Zeile ausgeblendet wird, und das sollte die akzeptierte Antwort sein.
Testmuster

8

Anstatt mit der Rasterzeile herumzuspielen, können Sie die Visibility-Eigenschaft der Steuerelemente (Felder in der Zeile) auf "Reduziert" setzen. Dadurch wird sichergestellt, dass die Steuerelemente keinen Platz beanspruchen. Wenn Sie die Rasterzeilenhöhe = "Auto" haben, wird die Zeile ausgeblendet, da alle Steuerelemente in der Zeile Sichtbarkeit = "Reduziert" haben.

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

Diese Methode ist besser, da die Sichtbarkeit der Steuerelemente mithilfe eines Konverters an eine Eigenschaft gebunden werden kann.


7

Mach das einfach:
rowToHide.Height = new GridLength(0);

Wenn Sie verwenden, visibility.Collapsemüssen Sie es für jedes Mitglied der Zeile festlegen.


6

Stellen Sie die Sichtbarkeit des Inhalts der Zeile auf " Visibility.CollapsedAusgeblendet" ein. Dadurch nimmt der Inhalt keinen Platz mehr ein und die Zeile wird entsprechend verkleinert.


1
Ich habe woanders jemanden gesehen, der die Zeilensichtbarkeit erwähnt hat. Aber die Zeile hat keinen Sichtbarkeitsstatus? Das Festlegen aller Elemente in der Zeile auf Sichtbarkeit.Collapsed hat jedoch funktioniert.
Richard

5
@Richard: Sie können RowDefinition.Visibility nicht festlegen, da es sich nicht um ein UIElement handelt. Sie können jedoch den gesamten Inhalt für die Zeile (oder jede Spalte in der Zeile) in einem einzelnen Container ablegen und die Sichtbarkeit dieses Containers festlegen.
Reed Copsey

1
Was ist, wenn Ihre Rasterzeile keinen Inhalt, aber eine feste Höhe hat? Gibt es eine bequeme Möglichkeit zum Ein- / Ausblenden?
Kevinarpe

4

Ich hatte eine ähnliche Idee, als ich RowDefinition erbte (nur aus Interesse)

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

Jetzt können Sie es wie folgt verwenden:

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

und umschalten mit

RowToHide.IsHidden = !RowToHide.IsHidden;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.