Ẩn hàng lưới trong WPF


94

Tôi có một biểu mẫu WPF đơn giản với một Gridkhai báo trên biểu mẫu. Điều này Gridcó một loạt các hàng:

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

Hàng có tên rowToHidechứa một vài trường đầu vào và tôi muốn ẩn hàng này sau khi tôi phát hiện ra mình không cần những trường này. Nó đủ đơn giản để chỉ đặt Visibility = Hiddenthành tất cả các mục trong hàng, nhưng hàng vẫn chiếm không gian trong Grid. Tôi đã thử thiết lập Height = 0các mục, nhưng điều đó dường như không hoạt động.

Bạn có thể nghĩ về nó như thế này: Bạn có một biểu mẫu, trong đó bạn có một trình đơn thả xuống nói "Hình thức thanh toán", và nếu người đó chọn "Tiền mặt", bạn muốn ẩn hàng chứa chi tiết Thẻ. Nó không phải là một tùy chọn để bắt đầu biểu mẫu với điều này đã bị ẩn.


1
xem mẹo này trên Tầm nhìn trở thành một hệ thống 3 nhà nước (trong những lời khuyên chủ đề WPF): stackoverflow.com/questions/860193/wpf-simple-tips-and-tricks/...
Metro Smurf

Những thứ tuyệt vời ... Nếu bạn đặt nó xuống như một câu trả lời, tôi sẽ đánh dấu điều đó ...
Richard

Câu trả lời:


88

Hàng không có thuộc tính Hiển thị, vì vậy, như những người khác đã nói, bạn cần đặt Chiều cao. Một tùy chọn khác là sử dụng trình chuyển đổi, trong trường hợp bạn cần chức năng này trong nhiều chế độ xem:

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

Và sau đó ở chế độ xem thích hợp <Grid.RowDefinition>:

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

10
UpVoted - Trình chuyển đổi cho phép tất cả điều này được khai báo trong Xaml. Tôi thường ghét sử dụng mã phía sau để tìm kiếm nội dung trực quan.
Allen

1
Điều này khá hữu ích và có thể dễ dàng mở rộng. Tôi đề nghị gọi nó BoolToGridLengthConvertervà thêm VisibleLength-Property, để trở lại (bool)value == true. Đó là cách bạn cũng có thể sử dụng lại nó với Autovà bất kỳ giá trị cố định nào.
LuckyLikey

1
Câu trả lời chính xác. Tôi cho rằng ý của bạn là IsDisplayedRow, không phải IsHiddenRow.
NielW

72

Giải pháp tốt nhất và rõ ràng để thu gọn hàng hoặc cột là sử dụng DataTrigger để trong trường hợp của bạn:

<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
Tôi thích cách tiếp cận này vì bạn không cần mã C # bổ sung.
user11909

1
Đừng quên triển khai INotifyPropertyChangedmã phía sau của bạn để nó hoạt động khi SomeBoolPropertyđược thay đổi :).
benichka

55

Bạn cũng có thể làm điều này bằng cách tham chiếu Hàng trong Lưới và sau đó thay đổi Chiều cao của chính hàng đó.

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

Mặc dù tính năng Thu gọn các phần tử trong Grid cũng hoạt động, điều này đơn giản hơn một chút nếu bạn có nhiều mục trong Grid không có phần tử bao quanh có thể thu gọn. Điều này sẽ cung cấp một sự thay thế tốt.


2
Điều này cũng có lợi thế khi làm việc với các hàng sử dụng ký hiệu dấu sao!
Johny Skovdal

1
Làm điều này trong mã là giải pháp rõ ràng nhất, dễ đọc nhất. Có lẽ hãy thêm một nhận xét sau RowDefinition, như<RowDefinition Height="*" /><!-- Height set in code behind -->
Kay Zed,

2
Tôi không nghĩ đây là giải pháp rõ ràng và dễ đọc nhất vì mã chức năng được chia thành hai tệp riêng biệt. Trên thực tế, tất cả đều có thể được thực hiện với XAML thuần túy - hãy xem câu trả lời của tôi.
Lukáš Koten

Nhu cầu của tôi hơi khác và trong C # nhưng ví dụ này đã chỉ cho tôi đúng hướng. Cảm ơn!
nrod

30

Để tham khảo, Visibilitylà kiểu liệt kê System.Windows.Visibility ba trạng thái :

  • Hiển thị - Phần tử được hiển thị và tham gia vào bố cục.
  • Đã thu gọn - Phần tử ẩn và không tham gia vào bố cục. Hiệu quả cung cấp cho nó chiều cao và chiều rộng bằng 0 và hoạt động như thể nó không tồn tại.
  • Ẩn - Phần tử vô hình nhưng vẫn tiếp tục tham gia vào bố cục.

Xem mẹo này và các mẹo khác trên chuỗi Mẹo và Thủ thuật WPF .


1
Đặt tất cả các mục trong hàng thành Visibility.Collapsed đã hoạt động, cảm ơn.
Richard

1
Tôi đã phản đối điều này vì tôi nghĩ câu trả lời của @ TravisPUK chứa một giải pháp rõ ràng hơn.
testpattern

11
@testpattern - phiếu phản đối thường được sử dụng cho các câu trả lời sai. Nếu câu trả lời khác tốt hơn, chỉ cần ủng hộ nó.
Metro Smurf

6
@MetroSmurf đủ công bằng. Có thể cho rằng câu trả lời của bạn là không đúng vì RowDefinition không có thuộc tính cho Visibility. TravisPUK chỉ ra cách ẩn một hàng và đó phải là câu trả lời được chấp nhận.
testpattern

8

Thay vì loay hoay với Hàng lưới, bạn có thể đặt thuộc tính Hiển thị của Điều khiển (các trường trong hàng) thành "Đã thu gọn". Điều này sẽ đảm bảo rằng các điều khiển không chiếm bất kỳ khoảng trống nào và nếu bạn có Grid Row Height = "Auto", thì hàng đó sẽ bị ẩn vì tất cả các điều khiển trong hàng có 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>

Phương pháp này tốt hơn vì Khả năng hiển thị của các điều khiển có thể được liên kết với một số thuộc tính với sự trợ giúp của Bộ chuyển đổi.


7

Đơn giản chỉ cần làm điều này:
rowToHide.Height = new GridLength(0);

nếu u sẽ sử dụng visibility.Collapsethì u phải đặt nó cho mọi thành viên của hàng.


6

Đặt khả năng hiển thị nội dung của Hàng thành Visibility.Collapsedthay vì Ẩn. Điều này sẽ làm cho nội dung ngừng chiếm dung lượng và hàng sẽ thu nhỏ lại một cách thích hợp.


1
Tôi đã thấy ở đâu đó một người khác đề cập đến Chế độ hiển thị hàng. Nhưng Hàng không có trạng thái hiển thị? Đặt tất cả các Mục trong Hàng thành Hiển thị. Mặc dù vậy, đã hoạt động.
Richard

5
@Richard: Bạn không thể đặt RowDefinition.Visibility vì nó không phải là UIElement - nhưng bạn có thể đặt tất cả nội dung của mình cho hàng (hoặc mỗi cột trong hàng) vào một vùng chứa duy nhất và đặt độ hiển thị của vùng chứa đó.
Reed Copsey

1
Điều gì sẽ xảy ra nếu hàng lưới của bạn không có bất kỳ nội dung nào, nhưng có chiều cao cố định? Có cách nào thuận tiện để hiển thị / ẩn không?
kevinarpe 12/12/12

4

Tôi đã có một ý tưởng tương tự bằng cách kế thừa RowDefinition (chỉ để quan tâm)

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

Bây giờ bạn có thể sử dụng nó như sau:

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

và chuyển đổi với

RowToHide.IsHidden = !RowToHide.IsHidden;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.