我有一个 GroupBox(包含一个 ListBox)和一个 Expander,每个都位于网格内各自的行中:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="My List">
<ListBox>
...
</ListBox>
</GroupBox>
<Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
<Expander.Header>
<TextBlock FontWeight="Bold">My Expander</TextBlock>
</Expander.Header>
<StackPanel Margin="5 5 5 5">
<TextBlock TextWrapping="Wrap">
Lots<LineBreak />
and<LineBreak />
lots<LineBreak />
of<LineBreak />
lines.
</TextBlock>
<TextBlock TextWrapping="Wrap">
More <Run FontFamiliy="Courier">Stuff</Run> here.
</TextBlock>
</StackPanel>
</Expander>
<Grid>
想要的行为:
我希望 GroupBox(带有 ListBox)使用父级(例如父级是 Window)定义的 Grid 的所有可用空间减去(关闭的)Expander 的大小。如果用户打开 Expander,它应该让 GroupBox 收缩(甚至完全折叠)并为 Expander 留出空间。
但是,我想将 Expander 的高度限制为允许 Grid 扩展而不会导致溢出的最大可用高度。如果扩展器的高度因此受到限制,它应该开始显示垂直滚动条。
当前行为:
使用我当前的 XAML 代码,扩展器将使网格溢出,即它将扩展到可用空间之外(因此也不会显示垂直滚动条。)
问题简而言之:
如何设置网格,以便将扩展器的高度限制为网格的最大可用高度?
第一个解决方案: 我能想到的简单解决方案是用只读 TextBox 代替 Expander->TextBlock 并使用 VerticalScrollBarVisibility= Auto 这是示例代码;
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="My List">
<ListBox>
...
</ListBox>
</GroupBox>
<Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
<Expander.Header>
<TextBlock FontWeight="Bold">My Expander</TextBlock>
</Expander.Header>
<StackPanel Margin="5 5 5 5">
<TextBox TextWrapping="Wrap" Margin="0,0,0,30" MaxHeight="290" HorizontalAlignment="Left" VerticalScrollBarVisibility="Auto" IsReadOnly="True" >
<TextBox.Text>
Lorem ipsum dolor sit amet...
Very Very long text
</TextBox.Text>
</TextBox>
</StackPanel>
</Expander>
</Grid>
您唯一需要注意的是 TextBox 的 MaxHeight。 MaxHeight 应为(窗口高度 - 扩展器高度)。
第二个解决方案: 如果必须使用 TextBlock,您可以在 TextBlock 周围包裹一个scrollViewer,并将其 MaxHeight 设置为(窗口高度 - Expander 高度)
首先:添加对您的XAML窗口的引用
xmlns:local="cld-namespace:AutoSizing"
第二:像这样创建转换器的实例。
<Window.Resources>
<local:SizeModifierConverter x:Key="SizeModifierConverter"/>
</Window.Resources>
第三:在ScrollViewer中使用Binding和Covnverter
<ScrollViewer VerticalScrollBarVisibility="Auto"
MaxHeight="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
Converter={StaticResource SizeModifierConverter}, ConverterParameter= -50}" >
<StackPanel Margin="5 5 5 5">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20" HorizontalAlignment="Left" >
Long text with Run Linereak and hyperlinks...
</TextBlock>
<TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20" HorizontalAlignment="Left" >
Long text with Run Linereak and hyperlinks...
</TextBlock>
</StackPanel>
</ScrollViewer>
转换器将如下所示;
public class SizeModifierConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double ActualWidth;
if(double.TryParse(value.ToString(), out ActualWidth))
{
double AdjustValue = 0;
if (double.TryParse(parameter.ToString(), out AdjustValue))
{
return (ActualWidth + AdjustValue);
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
希望这会有所帮助!
我想出了一个不需要任何代码隐藏的解决方案。我的解决方案使用 DockPanel:
<DockPanel>
<Expander DockPanel.Dock="Bottom">
<Expander.Header>
<TextBlock FontWeight="Bold">My Expander</TextBlock>
</Expander.Header>
<ScrollViewer>
<StackPanel Margin="5 5 5 5">
<TextBlock TextWrapping="Wrap">
Lots<LineBreak />
and<LineBreak />
lots<LineBreak />
of<LineBreak />
lines.
</TextBlock>
<TextBlock TextWrapping="Wrap">
More <Run FontFamiliy="Courier">Stuff</Run> here.
</TextBlock>
</StackPanel>
</ScrollViewer>
</Expander>
<GroupBox Header="My List" DockPanel.Dock="Top">
<ListBox>
...
</ListBox>
</GroupBox>
<Grid>
我没有足够的观点发表评论,所以我将其发布在那里。 AnandShanbhag 提供的解决方案效果很好,只需要添加一个检查,看看 ActualWidth + AdjustValue 是否低于 0。如果是这种情况,则返回 0。在我的例子中,将窗口缩小到很小,由于负值,应用程序崩溃了。
public class SizeModifierConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double ActualWidth;
if (double.TryParse(value.ToString(), out ActualWidth))
{
double AdjustValue = 0;
if (double.TryParse(parameter.ToString(), out AdjustValue))
{
var result = ActualWidth + AdjustValue;
if (result < 0)
{
result = 0;
}
return result;
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}