You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF Grid布局需求:折叠下方网格时上方占满空间

WPF Grid行高动态适配问题

我在WPF表单中定义了如下布局:

<Grid Margin="380,69,10,50" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <TextBlock Text="Script Preview" TextWrapping="Wrap" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <TextBox Style="{StaticResource TxtRoundCorner}" IsReadOnly="True" AcceptsReturn="True" TextWrapping="Wrap" Text="{Binding SelectedScript.Script}" Margin="0,20,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
    </Grid>
    <Grid Grid.Row="1" Visibility="{Binding ShowParmFilled}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <TextBlock Text="Script Parameters Filled In" TextWrapping="Wrap" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <TextBox Style="{StaticResource TxtRoundCorner}" IsReadOnly="True" AcceptsReturn="True" TextWrapping="Wrap" Text="{Binding AfterParmReplace}" Margin="0,20,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
    </Grid>
</Grid>

并非所有脚本都包含参数,只有填写参数后才显示下方的预览区域,因此编写了如下方法控制可见性:

public void SetScriptParmStateDisplay()
{
    ShowParmInfo = Visibility.Collapsed;
    ShowParmError = Visibility.Collapsed;
    ShowParmFilled = Visibility.Collapsed;
    if (scriptVarErrors.Any())
    {
        ParametersSet = Brushes.Red;
        ShowParmError = Visibility.Visible;
        ShowParmInfo = Visibility.Visible;
    }
    else if (FoundParameters.Any(_ => string.IsNullOrWhiteSpace(_.Value)))
    {
        ShowParmInfo = Visibility.Visible;
        ParametersSet = Brushes.Gold;
    }
    else
    {
        ShowParmInfo = Visibility.Visible;
        ShowParmFilled = Visibility.Visible;
        ParametersSet = Brushes.Black;
    }
}

我尝试过两种RowDefinitions设置,但都无法满足需求:

  • 第一种设置:
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    
    问题:始终将空间均分,无论下方网格是否折叠。
  • 第二种设置:
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    
    问题:顶部TextBox按内容尺寸显示,下方网格会超出窗口限制。

期望实现的效果:当下方网格折叠时,顶部网格填充所有可用空间;当下方网格可见时,两者均分空间。猜测需要绑定行高并手动控制,寻求正确实现方式。


解决方案

可以通过绑定RowDefinition的Height属性到ViewModel中的动态属性,结合可见性状态来调整行高:

  1. 在ViewModel中添加两个属性用于控制行高(需实现INotifyPropertyChanged接口):
public GridLength TopRowHeight { get; set; }
public GridLength BottomRowHeight { get; set; }

// 示例PropertyChanged触发方法
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
  1. 在SetScriptParmStateDisplay方法中更新行高:
public void SetScriptParmStateDisplay()
{
    ShowParmInfo = Visibility.Collapsed;
    ShowParmError = Visibility.Collapsed;
    ShowParmFilled = Visibility.Collapsed;
    
    if (scriptVarErrors.Any())
    {
        ParametersSet = Brushes.Red;
        ShowParmError = Visibility.Visible;
        ShowParmInfo = Visibility.Visible;
        TopRowHeight = new GridLength(1, GridUnitType.Star);
        BottomRowHeight = new GridLength(0);
    }
    else if (FoundParameters.Any(_ => string.IsNullOrWhiteSpace(_.Value)))
    {
        ShowParmInfo = Visibility.Visible;
        ParametersSet = Brushes.Gold;
        TopRowHeight = new GridLength(1, GridUnitType.Star);
        BottomRowHeight = new GridLength(0);
    }
    else
    {
        ShowParmInfo = Visibility.Visible;
        ShowParmFilled = Visibility.Visible;
        ParametersSet = Brushes.Black;
        TopRowHeight = new GridLength(1, GridUnitType.Star);
        BottomRowHeight = new GridLength(1, GridUnitType.Star);
    }
    
    OnPropertyChanged(nameof(TopRowHeight));
    OnPropertyChanged(nameof(BottomRowHeight));
}
  1. 修改XAML中的RowDefinitions,绑定行高:
<Grid.RowDefinitions>
    <RowDefinition Height="{Binding TopRowHeight}"/>
    <RowDefinition Height="{Binding BottomRowHeight}"/>
</Grid.RowDefinitions>

这样,当下方网格需要隐藏时,将其行高设为0,顶部行占满所有空间;当下方网格可见时,两行均分空间。

另外,也可以使用IValueConverter将ShowParmFilled的可见性转换为对应的行高,避免在ViewModel中直接处理GridLength:

  1. 实现转换器:
public class VisibilityToGridLengthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility visibility)
        {
            var isInverse = parameter?.ToString() == "Inverse";
            return (visibility == Visibility.Visible && !isInverse) || (visibility != Visibility.Visible && isInverse)
                ? new GridLength(1, GridUnitType.Star) 
                : new GridLength(0);
        }
        return new GridLength(0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. 在XAML中声明转换器并使用:
<Window.Resources>
    <local:VisibilityToGridLengthConverter x:Key="VisibilityToGridLengthConverter"/>
</Window.Resources>

<Grid.RowDefinitions>
    <RowDefinition Height="{Binding ShowParmFilled, Converter={StaticResource VisibilityToGridLengthConverter}, ConverterParameter='Inverse'}"/>
    <RowDefinition Height="{Binding ShowParmFilled, Converter={StaticResource VisibilityToGridLengthConverter}}"/>
</Grid.RowDefinitions>

两种方式都能实现需求,选择适合自己项目架构的方式即可。


内容的提问来源于stack exchange,提问作者Nottoc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 15:54:54