Ukryj wiersz siatki w WPF

96

Mam prosty formularz WPF z Gridzadeklarowanym w formularzu. To Gridma kilka wierszy:

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

Wiersz o nazwie rowToHidezawiera kilka pól wejściowych i chcę ukryć ten wiersz po wykryciu, że nie potrzebuję tych pól. Wystarczy ustawić Visibility = Hiddenwszystkie elementy w wierszu, ale wiersz nadal zajmuje miejsce w pliku Grid. Próbowałem ustawić Height = 0elementy, ale to nie działało.

Możesz o tym pomyśleć w ten sposób: Masz formularz, w którym masz listę rozwijaną z napisem „Rodzaj płatności”, a jeśli osoba wybierze opcję „Gotówka”, chcesz ukryć wiersz zawierający dane karty. Nie można już uruchomić formularza z tym ukrytym.

Richard
źródło
1
zobacz tę wskazówkę na temat widoczności jako systemu 3-stanowego (w wątku wskazówek WPF): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/…
Metro Smurf
Wspaniałe rzeczy ... Gdybyś zapisał to jako odpowiedź, zaznaczyłbym to ...
Richard
Spójrz również na tę wskazówkę: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
Domokun

Odpowiedzi:

89

Wiersz nie ma właściwości Widoczność, więc jak powiedzieli inni, musisz ustawić wysokość. Inną opcją jest użycie konwertera, na wypadek gdybyś potrzebował tej funkcjonalności w wielu widokach:

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

A potem w odpowiednim widoku <Grid.RowDefinition>:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>
wzór testu
źródło
10
UpVoted - konwertery pozwalają na to wszystko jako deklaratywne w Xaml. Generalnie nienawidzę używania kodu do majstrowania przy wizualnych rzeczach.
Allen
1
Jest to całkiem przydatne i można je łatwo rozszerzyć. Proponuję nazwać to BoolToGridLengthConverteri dodać VisibleLength-Property, aby powrócić (bool)value == true. W ten sposób możesz również użyć go ponownie z Autodowolną wartością ustaloną.
LuckyLikey
1
Świetna odpowiedź. Zakładam, że miałeś na myśli IsDisplayedRow, a nie IsHiddenRow.
NielW
73

Najlepszym i czystym rozwiązaniem zwinięcia wierszy lub kolumn jest użycie DataTrigger, więc w twoim przypadku:

<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
źródło
5
Podoba mi się to podejście, ponieważ nie potrzebujesz dodatkowego kodu C #.
user11909
1
Nie zapomnij zaimplementować INotifyPropertyChangedw swoim kodzie, aby działał, gdy SomeBoolPropertyzostanie zmieniony :).
benichka
55

Możesz to również zrobić, odwołując się do wiersza w siatce, a następnie zmieniając wysokość samego wiersza.

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

Chociaż zwijanie elementów w siatce również działa, jest to nieco prostsze, jeśli masz wiele elementów w siatce, które nie mają otaczającego elementu, który można zwinąć. Stanowiłoby to dobrą alternatywę.

TravisPUK
źródło
2
Ma to również tę zaletę, że pracuje z wierszami używającymi notacji gwiazdkowej!
Johny Skovdal
1
Robienie tego w kodzie jest najwyraźniejszym i najbardziej czytelnym rozwiązaniem. Być może dodaj komentarz po RowDefinition, na przykład<RowDefinition Height="*" /><!-- Height set in code behind -->
Kay Zed
2
Nie sądzę, aby było to najbardziej przejrzyste i najbardziej czytelne rozwiązanie, ponieważ kod funkcjonalny jest podzielony na dwa oddzielne pliki. W rzeczywistości wszystko to można zrobić za pomocą czystego XAML - zobacz moją odpowiedź.
Lukáš Koten
Moje potrzeby były nieco inne i napisane w C #, ale ten przykład wskazał mi właściwy kierunek. Dzięki!
nrod
30

Dla odniesienia Visibilityjest to wyliczenie z trzema stanami System.Windows.Visibility :

  • Widoczny - element jest renderowany i uczestniczy w układzie.
  • Zwinięty - element jest niewidoczny i nie uczestniczy w układzie. Skutecznie nadając mu wysokość i szerokość 0 i zachowując się tak, jakby nie istniał.
  • Ukryty - element jest niewidoczny, ale nadal uczestniczy w układzie.

Zobacz tę wskazówkę i inne wskazówki w wątku Porady i wskazówki WPF .

Metro Smurf
źródło
1
Ustawiam wszystkie elementy w rzędzie na Widoczność Zwinięte zadziałało, dzięki.
Richard,
1
Głosowałem w dół, ponieważ myślę, że odpowiedź @ TravisPUK zawiera jaśniejsze, bardziej oczywiste rozwiązanie.
wzór testowy
11
@testpattern - głosy przeciwne są zwykle używane w przypadku nieprawidłowych odpowiedzi. Jeśli druga odpowiedź jest lepsza, po prostu ją zagłosuj.
Metro Smurf
6
@MetroSmurf wystarczy. Prawdopodobnie twoja odpowiedź nie jest poprawna, ponieważ RowDefinition nie ma właściwości Visibility. TravisPUK pokazuje, jak ukryć wiersz i to powinna być akceptowana odpowiedź.
testpattern
8

Zamiast bawić się wierszem siatki, można ustawić właściwość Widoczność elementów sterujących (pól w wierszu) na „Zwinięty”. Zapewni to, że kontrolki nie zajmą miejsca i jeśli masz Wysokość wiersza siatki = „Auto”, wiersz zostanie ukryty, ponieważ wszystkie kontrolki w wierszu mają Widoczność = „Zwinięty”.

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

Ta metoda jest lepsza, ponieważ Widoczność kontrolek można powiązać z jakąś właściwością za pomocą konwertera.

user3726565
źródło
7

Po prostu zrób to:
rowToHide.Height = new GridLength(0);

jeśli użyjesz, visibility.Collapsemusisz ustawić to dla każdego członka wiersza.

NAZWA UŻYTKOWNIKA
źródło
6

Ustaw widoczność zawartości wiersza Visibility.Collapsedzamiast Ukryte. Spowoduje to, że zawartość przestanie zajmować miejsce, a wiersz odpowiednio się zmniejszy.

Reed Copsey
źródło
1
Widziałem gdzieś indziej, ktoś wspomniał o widoczności rzędów. Ale Row nie ma stanu widoczności? Ustawienie wszystkich elementów w rzędzie na Widoczność zadziałało.
Richard
5
@Richard: Nie możesz ustawić RowDefinition.Visibility, ponieważ nie jest to element UIElement - ale możesz umieścić całą zawartość wiersza (lub każdej kolumny w wierszu) w jednym kontenerze i ustawić widoczność tego kontenera.
Reed Copsey
1
Co się stanie, jeśli wiersz siatki nie ma żadnej treści, ale ma stałą wysokość? Czy istnieje wygodny sposób na pokazanie / ukrycie?
kevinarpe
4

Miałem podobny pomysł, dziedzicząc RowDefinition (tylko dla zainteresowania)

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

Teraz możesz go używać w następujący sposób:

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

i przełączaj z

RowToHide.IsHidden = !RowToHide.IsHidden;
Matt
źródło