WPF GridSplitter 调整大小后

6

使用网格分隔器调整网格大小后,其他行折叠时,该行将不会重新占用空间。

我在主细节视图中有以下网格,其中包含三行。顶部是数据网格,中间是分隔器,最后一行是内容控件视图。分隔器上有一个关闭按钮,可以折叠详细信息。所有这些都可以正常工作,但用户使用网格分隔器调整大小后出现问题。

    <Grid Margin="3,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Style="{StaticResource CollapsableRow}"/><!-- Splitter Here -->
        <RowDefinition Style="{StaticResource CollapsableRow}"/>
    </Grid.RowDefinitions>
The GridSplitter样式:
    <Style x:Key="gridSplitterStyle" TargetType="{x:Type GridSplitter}">
    <Setter Property="Visibility" Value="{Binding IsItemSelected, Converter={StaticResource BoolToShow},ConverterParameter='Visible|Collapsed'}" />
    <Setter Property="Width" Value="Auto"/>
    <Setter Property="Height" Value="14"/>
    <Setter Property="HorizontalAlignment" Value="Stretch"/>
    <Setter Property="Border.BorderBrush" Value="#FF6593CF" />
    <Setter Property="Border.BorderThickness" Value="0,1,0,0" />
    <Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
    <Setter Property="UIElement.Focusable" Value="False" />
    <Setter Property="Control.Padding" Value="7,7,7,7" />
    <Setter Property="Cursor" Value="SizeNS" /></Style>

就像我之前说的那样,如果不使用网格分隔器进行调整大小,折叠功能是正常工作的。但是在使用网格分隔器调整大小后,空白区域会保留。

编辑: H.B. 和 codenaked 提出了简单而一致的建议,我尝试在数据触发器中实现它们,但没有成功:

<Style x:Key="CollapsableRow" TargetType="{x:Type RowDefinition}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding SelectedItem, Converter={StaticResource IsNullConverter}}" Value="True">
            <Setter Property="RowDefinition.Height" Value="0"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding SelectedItem, Converter={StaticResource IsNullConverter}}" Value="False">
            <Setter Property="RowDefinition.Height" Value="Auto"/>
        </DataTrigger>            
    </Style.Triggers>
</Style>   
4个回答

7

由于网格分隔符和详细信息已经被隐藏,可见性是重置下一行定义高度的明显选择。

 /// <summary>
/// Grid splitter that show or hides the following row when the visibility of the splitter is changed. 
/// </summary>
public class HidableGridSplitter : GridSplitter { 

    GridLength height;

    public HidableGridSplitter()
    {
        this.IsVisibleChanged += HideableGridSplitter_IsVisibleChanged;
        this.Initialized += HideableGridSplitter_Initialized;
    }

    void HideableGridSplitter_Initialized(object sender, EventArgs e)
    {
        //Cache the initial RowDefinition height,
        //so it is not always assumed to be "Auto"
        Grid parent = base.Parent as Grid;
        if (parent == null) return;
        int rowIndex = Grid.GetRow(this);
        if (rowIndex + 1 >= parent.RowDefinitions.Count) return;
        var lastRow = parent.RowDefinitions[rowIndex + 1];
        height = lastRow.Height;
    }

    void HideableGridSplitter_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        Grid parent = base.Parent as Grid;
        if (parent == null) return;

        int rowIndex = Grid.GetRow(this);

        if (rowIndex + 1 >= parent.RowDefinitions.Count) return;

        var lastRow = parent.RowDefinitions[rowIndex + 1];

        if (this.Visibility == Visibility.Visible)
        {
            lastRow.Height = height;
        }
        else
        {
            height = lastRow.Height; 
            lastRow.Height = new GridLength(0);
        }

    }

3

1

如果您使用GridSplitter,则高度不再是Auto,而是具体值。您需要手动更改这些值,可以使用样式或事件和代码后台来实现,例如,双击时重置自动大小列:

private void ColumnSplitter_DoubleClick(object sender, MouseButtonEventArgs e)
{
    if (!ColumnTreeView.Width.IsAuto) ColumnTreeView.Width = new GridLength();
}

需要在代码中设置网格长度。但是在这种情况下,双击不起作用。网格分隔器正在进行样式设置,实际上是分隔器上的一个按钮来关闭。我选择重写网格分隔器并在那里设置parent.height。 - Ryan Mrachek
我的代码只是一个例子,我从未期望你在“双击”时不做任何事情。 - H.B.

0

根据您提供的内容,GridSplitter将调整前一行和后一行的大小。您可以通过以下代码看到其效果:

<Grid Margin="3,0">
    <Grid.RowDefinitions>
        <RowDefinition x:Name="row0" Height="*" />
        <RowDefinition Height="Auto" />
        <RowDefinition x:Name="row2" Height="Auto" />
    </Grid.RowDefinitions>
    <Border Background="Red" >
        <TextBlock Text="{Binding ElementName=row0, Path=Height}" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>
    <GridSplitter Grid.Row="1" Style="{StaticResource gridSplitterStyle}" HorizontalAlignment="Stretch" />
    <Border Background="Blue" Grid.Row="2" MinHeight="50">
        <TextBlock Text="{Binding ElementName=row2, Path=Height}" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>
</Grid>

最后一行的尺寸实际上会从“自动”更改为固定高度。因此,即使您折叠该行中的内容,它仍将占用指定的空间。您需要将该行重置为Height="Auto"才能真正将其与其内容折叠。

我喜欢你和H.B.的建议,并在行上实现了一个样式触发器来做到这一点: - Ryan Mrachek
没成功 :( 因为 rowDefinition 需要一个新的 GridLength 实例来设置。 - Ryan Mrachek
@Ryan - 不太确定我理解了没有。如果你设置 this.row2.Height = GridLength.Auto; 那么它会被重置。 - CodeNaked

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接