Скрыть строку сетки в WPF

95

У меня есть простая форма WPF с Gridобъявленным в форме. У этого Gridесть несколько строк:

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

Строка с именем rowToHideсодержит несколько полей ввода, и я хочу скрыть эту строку после того, как обнаружу, что эти поля мне не нужны. Достаточно просто установить Visibility = Hiddenвсе элементы в строке, но строка по-прежнему занимает место в Grid. Я попытался установить Height = 0элементы, но, похоже, это не сработало.

Вы можете думать об этом так: у вас есть форма, в ней есть раскрывающийся список с надписью «Тип платежа», и если человек выбирает «Наличные», вы хотите скрыть строку, содержащую данные карты. Невозможно запустить форму с этим уже скрытым.

Ричард
источник
1
см. этот совет о том, что Visibility является системой с тремя состояниями (в ветке советов WPF): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/…
Metro Smurf
Блестящий материал ... Если бы вы записали это как ответ, я бы отметил, что ...
Ричард
Также обратите внимание на этот совет: social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
Domokun

Ответы:

88

У строки нет свойства видимости, поэтому, как говорили другие, вам нужно установить высоту. Другой вариант - использовать конвертер, если вам нужна эта функция во многих представлениях:

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

А затем в соответствующем виде <Grid.RowDefinition>:

<RowDefinition Height="{Binding IsHiddenRow, Converter={StaticResource BoolToGridRowHeightConverter}}"></RowDefinition>
тестовый шаблон
источник
10
UpVoted - конвертеры позволяют декларативно делать все это в Xaml. Я вообще ненавижу использовать код программной части, чтобы возиться с визуальными элементами.
Аллен
1
Это очень полезно, и его легко можно расширить. Я предлагаю назвать его BoolToGridLengthConverterи добавить VisibleLength-Property, чтобы вернуться (bool)value == true. Вот как вы также можете повторно использовать его с Autoлюбым фиксированным значением.
LuckyLikey
1
Отличный ответ. Я предполагаю, что вы имели в виду IsDisplayedRow, а не IsHiddenRow.
NielW
72

Лучшее и чистое решение для свертывания строк или столбцов - использовать DataTrigger, поэтому в вашем случае:

<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
Мне нравится этот подход, потому что вам не нужен дополнительный код C #.
user11909
1
Не забудьте реализовать INotifyPropertyChangedв своем коде, чтобы он работал при SomeBoolPropertyизменении :).
benichka 07
55

Вы также можете сделать это, указав строку в сетке, а затем изменив высоту самой строки.

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

Хотя сворачивание элементов в сетке также работает, это немного проще, если у вас есть много элементов в сетке, которые не имеют закрывающего элемента, который можно свернуть. Это было бы хорошей альтернативой.

TravisPUK
источник
2
Это также дает преимущество работы со строками, в которых используется звездочка!
Johny Skovdal
1
Выполнение этого в коде - самое ясное и наиболее читаемое решение. Возможно, добавлю комментарий после RowDefinition, вроде<RowDefinition Height="*" /><!-- Height set in code behind -->
Кей Зед
2
Я не думаю, что это самое ясное и удобочитаемое решение, поскольку функциональный код разделен на два отдельных файла. На самом деле все это можно сделать с помощью чистого XAML - см. Мой ответ.
Лукаш Котен
Мои потребности были немного другими и в C #, но этот пример указал мне правильное направление. Спасибо!
nrod
30

Для справки, Visibilityэто перечисление System.Windows.Visibility с тремя состояниями :

  • Видимый - элемент отображается и участвует в макете.
  • Свернут - элемент невидим и не участвует в макете. Фактически задает ему высоту и ширину 0 и ведет себя так, как будто его не существует.
  • Скрытый - элемент невидим, но продолжает участвовать в макете.

См. Этот совет и другие советы в ветке WPF Tips and Tricks .

Метро Смурф
источник
1
Установка для всех элементов в строке Visibility.Collapsed сработала, спасибо.
Ричард
1
Я отклонил это, потому что считаю, что ответ @TravisPUK содержит более четкое и очевидное решение.
testpattern
11
@testpattern - при неправильных ответах обычно используются отрицательные голоса. Если другой ответ лучше, просто проголосуйте за него.
Metro Smurf
6
@MetroSmurf достаточно честно. Возможно, ваш ответ неверен, потому что RowDefinition не имеет свойства для видимости. TravisPUK показывает, как скрыть строку, и это должен быть принятый ответ.
testpattern
8

Вместо того, чтобы возиться со строкой сетки, вы можете установить для свойства Visibility элементов управления (полей в строке) значение «Collapsed». Это гарантирует, что элементы управления не занимают места, и если у вас есть Grid Row Height = "Auto", то строка будет скрыта, так как все элементы управления в строке имеют 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>

Этот метод лучше, потому что видимость элементов управления может быть привязана к какому-либо свойству с помощью конвертера.

user3726565
источник
7

Просто сделайте это:
rowToHide.Height = new GridLength(0);

если вы будете использовать, visibility.Collapseто вам нужно установить его для каждого члена строки.

USER_NAME
источник
6

Установите видимость содержимого строки Visibility.Collapsedвместо «Скрытый». Это заставит контент перестать занимать место, а строка соответственно уменьшится.

Рид Копси
источник
1
Я видел где-то еще, что кто-то упоминал о видимости строк. Но у строки нет состояния видимости? Однако установка для всех элементов в строке Visibility.Collapsed сработала.
Ричард
5
@Richard: вы не можете установить RowDefinition.Visibility, поскольку это не UIElement, но вы можете поместить весь свой контент для строки (или каждого столбца в строке) в один контейнер и установить видимость этого контейнера.
Рид Копси,
1
Что, если ваша строка сетки не имеет содержимого, а имеет фиксированную высоту? Есть ли удобный способ показать / скрыть?
kevinarpe
4

У меня была аналогичная идея, унаследовав RowDefinition (просто для интереса)

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

Теперь вы можете использовать его следующим образом:

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

и переключиться с помощью

RowToHide.IsHidden = !RowToHide.IsHidden;
Мэтт
источник