扩展器、网格和列表框 = 无虚拟化

3
我有一个ListBox,它在Grid和Expander中。ListBox被绑定到一个IList上。
当我第一次展开Expander时,ListBox会处理IList中的所有项(可能是数千个),而不仅仅是屏幕上可见的项。
但是,如果我固定ListBox控件的高度,它将按预期工作,并且只访问IList中将要显示的那些项目。
实际上,虚拟化未起作用,尽管我相信这更与ListBox无法在准备内容项时确定高度有关。
XAML基本如下(为简化起见省略了一些内容)…
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Expander ExpandDirection="Right"
              Grid.Column="0"
              Grid.Row="0"
              Grid.RowSpan="2"
              Header="Documents"
              IsExpanded="False">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50" />
                </Grid.RowDefinitions>
            </Grid>
            <ListBox Name="listBox"
                     Grid.Row="1"
                     ItemsSource="{Binding Path=Items}"
                     SelectedIndex="{Binding Path=SelectedIndex}"
                     SelectedItem="{Binding Path=SelectedItem}"
                     SelectionMode="Single"
                     Width="250">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto" />
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Column="0"
                                       Style="{StaticResource prompt}">
                                <TextBlock.Text>
                                    <MultiBinding StringFormat="{}{0}{1:00000}">
                                        <Binding Path="..."
                                                 FallbackValue="0" />
                                        <Binding Path="..." />
                                    </MultiBinding>
                                </TextBlock.Text></TextBlock>
                            <TextBlock Grid.Column="1"
                                       Style="{StaticResource prompt}">
                                <TextBlock.Text>
                                    <Binding Path="ItemCount"
                                             StringFormat="{}{0} Items"
                                             FallbackValue="" />
                                </TextBlock.Text></TextBlock>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Expander>
    <v:DocumentView x:Name="documentView"
                    Grid.Column="1"
                    Grid.Row="0"
                    DocumentID="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=ViewModel.SelectedItem.ID}"
                    IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=IsActive}" />
    <StackPanel Grid.Column="1"
                Grid.Row="1"
                Style="{StaticResource buttonStackStyle}">
        <Button Command="{Binding Path=PreviousCommand}"
                Style="{StaticResource previousButtonStyle}" />
        <Button Command="{Binding Path=NextCommand}"
                Style="{StaticResource nextButtonStyle}" />
    </StackPanel>
</Grid>

有人能建议我如何将ListBox的高度设置为Grid.Row父级的ActualHeight吗?或者,有人能提供更好的解决方案吗?
谢谢。
1个回答

1

简短版:从扩展器中删除Grid.RowSpan

详细版:

背景:(概述)

当您定义RowDefinition的高度时,会发生三件事情,具体取决于您使用的单位类型:

  1. 像素 - 放置在该行中的任何UI元素都将传递定义的行高到元素的MeasureArrange方法中。
  2. 自动 - 网格将传递无限高度作为Measure,然后传递element.DesiredSize.Height作为Arrange
  3. 星号 - 网格将考虑所有具有像素和自动单位的行的高度;计算其可用高度剩余的高度,并将其除以为所有行定义的“总星数” - 这是一个星的高度;然后,根据其星定义的乘数分配每行高度;此高度传递给MeasureArrange方法。

对列定义应用相同的逻辑,只是涉及宽度而不是高度。

所以,星号定义是“停止”元素,像素定义也是“停止”,但它可以在渲染视图之外,自动定义是“让”元素成为任何大小。

所有这些逻辑都是递归的,因此您需要从两个方向思考(下面解释)。

在您的情况下

在一个方向上。 ListBox 在星号行中,因此它将被停止。父网格也已停止(因为展开器模板使用的是DockPanel,这也是一个“停止面板”)。展开器被定义为从星号行开始,但跨越到自动行 - 这意味着它将被允许在高度上增长到无限大。哎呀...该反转了。

现在是反向方向。展开器未停止,子网格未停止(因为网格假定其有无限高度可用),因此列表框未停止,列表框模板中的ScrollViewer未停止,因此它的ViewportHeight是无限的,对于排列项的VirtualizingStackPanel(是滚动查看器的子级)来说,这意味着所有项目都在视图中==渲染所有元素。

对于默认模板的 WPF 窗口,您可以始终假定窗口正在停止其子元素。因此,如果删除行跨度定义未解决问题,请继续向上遍历,直到找到另一个未停止其子高度的元素,并更改其定义或更改面板以防止高度无限增长(滚动查看器往往会创建这些行为,特别是隐藏在模板中的滚动查看器)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接