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> - 第二种设置:
问题:顶部TextBox按内容尺寸显示,下方网格会超出窗口限制。<Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions>
期望实现的效果:当下方网格折叠时,顶部网格填充所有可用空间;当下方网格可见时,两者均分空间。猜测需要绑定行高并手动控制,寻求正确实现方式。
解决方案
可以通过绑定RowDefinition的Height属性到ViewModel中的动态属性,结合可见性状态来调整行高:
- 在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)); }
- 在
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)); }
- 修改XAML中的
RowDefinitions,绑定行高:
<Grid.RowDefinitions> <RowDefinition Height="{Binding TopRowHeight}"/> <RowDefinition Height="{Binding BottomRowHeight}"/> </Grid.RowDefinitions>
这样,当下方网格需要隐藏时,将其行高设为0,顶部行占满所有空间;当下方网格可见时,两行均分空间。
另外,也可以使用IValueConverter将ShowParmFilled的可见性转换为对应的行高,避免在ViewModel中直接处理GridLength:
- 实现转换器:
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(); } }
- 在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
相关产品推荐
相关产品推荐

