将高度=自动的网格行约束到可见区域

时间:2012-11-15 10:07:29

标签: c# .net wpf .net-4.0 grid

考虑以下XAML:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*" MinHeight="100" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ListBox>
      <ListBox.Items>
        <ListBoxItem>a</ListBoxItem>
        <!-- Another 11 items -->
      </ListBox.Items>
    </ListBox>
    <ListBox Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible">
      <ListBox.Items>
        <ListBoxItem>1</ListBoxItem>
        <!-- Another 23 items -->
      </ListBox.Items>
    </ListBox>
  </Grid>
</Window>

第二行中的ListBox将垂直滚动条显示为已禁用,只是简单地切断了内容。

我希望它被限制在窗口的可见区域。怎么做到这一点?

Rational将第二个网格行的高度设置为Auto: 我希望第二个ListBox在没有滚动条的情况下显示其所有内容如果有足够的空间并且第一个ListBox应该占用剩余的空间。

1 个答案:

答案 0 :(得分:1)

我认为没有办法在纯XAML中做你想要的 - 你必须为两个列表框中的一个或另一个设置一个特定的高度,或者为它们设置固定的比例。

我认为你可以用后面代码中的一些代码做你想做的事。提供RowDefinitions和Listboxes名称,如下所示,并订阅GridSizedChanged事件:

<Grid SizeChanged="GridSizeChanged">
    <Grid.RowDefinitions>
        <RowDefinition x:Name="row1"/>
        <RowDefinition x:Name="row2"/>
    </Grid.RowDefinitions>
    <ListBox x:Name="lb1">
        <ListBox.Items>
            <ListBoxItem>a</ListBoxItem>
        </ListBox.Items>
    </ListBox>
    <ListBox x:Name="lb2" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible">
        <ListBox.Items>
            <ListBoxItem>1</ListBoxItem>
            <!-- Another 23 items -->
        </ListBox.Items>
    </ListBox>
</Grid>

然后按以下方式处理事件:

private void GridSizeChanged(object sender, SizeChangedEventArgs e)
{
    double newHeight = e.NewSize.Height;
    int lb1ItemCount = lb1.Items.Count;
    int lb2ItemCount = lb2.Items.Count;
    row1.Height = new GridLength(newHeight * lb1ItemCount / (lb1ItemCount + lb2ItemCount));
    row2.Height = new GridLength(newHeight * lb2ItemCount / (lb1ItemCount + lb2ItemCount));
}

这会将两个列表框的大小设置为与它们内部的项目数成比例。如果要为第一个列表框设置最小大小100,则必须先做一些工作来设置该大小,然后将第二个大小基于第一个大小的计算值。

修改 我想我已经编写了一个GridSizeChanged版本,可以完全满足您的需求。此版本将lb2的高度设置为除了前100px之外的整个网格(如果所需的列表框大小大于此值),或者如果它更小则仅设置为其自己的所需大小。然后第一个列表框将填充所有剩余空间,并且根据需要最小高度为100px,因为我们不允许lb2填充前100px。

private void GridSizeChanged(object sender, SizeChangedEventArgs e)
{
    lb2.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    double lb2DesiredHeight = lb2.DesiredSize.Height;

    double newHeight = e.NewSize.Height;
    double lb2AvailableHeight = newHeight - 100;

    double lb2ActualHeight = Math.Min(lb2DesiredHeight, lb2AvailableHeight);
    row1.Height = new GridLength(newHeight - lb2ActualHeight);
    row2.Height = new GridLength(lb2ActualHeight);
}