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.

Richard
quelle
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>
Testmuster
quelle
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>
Lukáš Koten
quelle
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.

TravisPUK
quelle
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 .

Metro Schlumpf
quelle
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.

user3726565
quelle
7

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

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

NUTZERNAME
quelle
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.

Reed Copsey
quelle
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;
Matt
quelle