Wpf 如何使网格行高度只占用它所需的空间,而且还受其容器中可用空间的约束?

Wpf 如何使网格行高度只占用它所需的空间,而且还受其容器中可用空间的约束?,wpf,layout,Wpf,Layout,我想要一个页眉,然后在它下面是一个ScrollViewer和一个ItemsControl,然后在它下面是一个页脚。比如: <Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="htt

我想要一个页眉,然后在它下面是一个
ScrollViewer
和一个
ItemsControl
,然后在它下面是一个页脚。比如:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid ShowGridLines="True">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="36"/>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0">Header</TextBlock>
        <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
            <ItemsControl>
                <ItemsControl.Items>
                    <TextBlock>Item 1</TextBlock>
                    <TextBlock>Item 2</TextBlock>
                    <TextBlock>Item 3</TextBlock>
                    <TextBlock>Item 4</TextBlock>
                    <TextBlock>Item 5</TextBlock>
                </ItemsControl.Items>
            </ItemsControl>
        </ScrollViewer>
        <TextBlock Grid.Row="2">Footer</TextBlock>
    </Grid>
</Window>

标题
项目1
项目2
项目3
项目4
项目5
页脚
以上几乎是我想要的,除了中间一排是贪婪的;即使窗户很高,它也会占据尽可能多的空间,将页脚推到窗户底部

如果我将中间行的定义更改为
Height=“Auto”
,它将完全占用它所需的空间量,即使空间不可用,因此
ScrollViewer
永远不会显示滚动条,如果窗口不够高,页脚将从窗口底部消失

如何使其在窗口高度足以容纳所有内容时,页脚位于
项目控件的正下方,但如果窗口高度不够,则
滚动查看器
会显示一个滚动条,页脚位于窗口底部

我不一定需要使用
网格
,但我也没有找到任何其他
面板
可以满足我的要求。例如,页眉设置为
DockPanel.Dock=“Top”
、页脚设置为
DockPanel.Dock=“Bottom”
DockPanel
和填充其余部分的
项控件的行为完全相同

我还试过其他一些东西:

  • 在页脚
    TextBlock
    上设置
    VerticalAlignment=“Stretch”
    :无更改
  • 使页脚行
    Height=“*”
    :仍然不是我想要的;页脚和
    ItemsControl
    具有相同的高度,因此页脚在大多数情况下会占用太多空间,或者如果使窗口非常短,则页脚会从窗口底部脱落

也许有一种更优雅的方式,但至少下面的方法在类似的情况下对我有效。它是关于计算ItemsControl中所有项目的实际高度,并根据需要调整网格的行高度

<Grid ShowGridLines="True" Loaded="Grid_Loaded">
    <Grid.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="36"/>
        </Style>
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*" Name="middlerow"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0">Header</TextBlock>
    <ScrollViewer Name="scv" Grid.Row="1" VerticalScrollBarVisibility="Auto">
        <ItemsControl x:Name="items" Height="Auto" VerticalAlignment="Top">
            <ItemsControl.Items>
                <TextBlock>Item 1</TextBlock>
                <TextBlock>Item 2</TextBlock>
                <TextBlock>Item 3</TextBlock>
                <TextBlock>Item 4</TextBlock>
            </ItemsControl.Items>
        </ItemsControl>
    </ScrollViewer>
    <TextBlock Grid.Row="2">Footer</TextBlock>
</Grid>

标题
项目1
项目2
项目3
项目4
页脚
在代码隐藏中:

private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        double height = 0;
        foreach (var item in items.Items)
        {
            height += (item as TextBlock).ActualHeight;
        }
        if (height < scv.ActualHeight)
        {
            middlerow.MaxHeight = height;
        }
    }
private void Grid\u已加载(对象发送方、路由目标方)
{
双倍高度=0;
foreach(items.items中的var项)
{
高度+=(项目作为文本块)。实际高度;
}
如果(高度
感谢您提出了如何执行此操作的概念,以及绑定行的
MaxHeight
的想法

XAML:


标题
项目1
项目2
项目3
项目4
项目5
页脚
代码隐藏:

private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        double height = 0;
        foreach (var item in items.Items)
        {
            height += (item as TextBlock).ActualHeight;
        }
        if (height < scv.ActualHeight)
        {
            middlerow.MaxHeight = height;
        }
    }
导入System.ComponentModel
类主窗口
实现INotifyPropertyChanged
公共事件PropertyChanged为PropertyChangedEventHandler实现INotifyPropertyChanged.PropertyChanged
公共只读属性项最大为双精度
得到
尺寸高度=0.0
尺寸icg=ic.ItemContainerGenerator
对于i=0到ic.Items.Count-1
高度+=DirectCast(icg.ContainerFromIndex(i),FrameworkElement)。实际高度
下一个
返回高度+6.0'6.0以说明边框的大小?不确定:(
结束
端属性
私有子Ic_SizeChanged(发送方作为对象,e作为SizeChangedEventArgs)
如果e.Heights发生了变化
RaiseEvent PropertyChanged(Me,新PropertyChangedEventArgs(“ItemsMaxHeight”))
如果结束
端接头
末级

在这个示例XAML中,我不需要将MaxHeight增加6,但是在我的实际应用程序中,如果我不增加一点额外的内容,
ScrollViewer
总是显示一个可以滚动一点的滚动条。不确定是什么原因导致了这种差异。

在发布我的问题后,我环顾四周,发现了更多的问题。这个答案更复杂,并且似乎对窗口上的其他控件的影响非常敏感。例如,它有一个神奇的数字“50或大约窗口标题栏大小的东西”。我怀疑如果要在网格上方添加另一个控件,则需要更改50。但是,我确实喜欢使用绑定,因此它会在需要时更新。您的解决方案简单得多,但它假设
ItemsControl
中的项都是
TextBlock
s。在我的示例中,我只是填充了
ItemsControl
使用
TextBlock
s,但在我的实际应用程序中,它是数据绑定的,并使用
DataTemplate
生成实际的可视控件。
Items
集合有我的数据对象,没有
ActualHeight
属性。但是,我找到了
ItemContainerGenerator
,它似乎解决了这个问题.我已经发布了一个答案,有点结合了你的解决方案和马库斯的另一个问题。