扩展器、网格和扩展器列表框 = 无虚拟化
我有一个列表框,在网格内,在扩展器内。 ListBox 绑定到 IList。
当我第一次展开 Expander 控件时,ListBox 会处理 IList 中的所有项目(可能有数千个),而不是仅处理屏幕上可见的项目。
但是,如果我修复 ListBox 控件的高度,它的行为将按预期进行,并且仅访问 IList 中可见的那些项目。
实际上,虚拟化不起作用,尽管我认为这与列表框在准备内容项时无法确定高度更相关。
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 吗?或者,有人可以提供更好的解决方案吗?
谢谢。
I have a ListBox, inside a Grid, inside an Expander. The ListBox is bound to an IList.
When I expand the Expander control for the first time, the ListBox processes all of the items in the IList (which can be thousands) instead of only processing the items that would be visible on the screen.
If however I fix the height of the ListBox control, it behaves as expected and only accesses those items in the IList that will be visible.
Effectively, the Virtualization is not working, though I believe that this is more related to the ListBox not being able to determine a height when the content items are being prepared.
The XAML is basically as follows (some stuff removed for simplification)...
<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>
Can anybody suggest how I might set the Height of the ListBox to the ActualHeight of the Grid.Row parent? Alternatively, can anybody provide a better solution?
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简短版本:从扩展器中删除
Grid.RowSpan
。长版本:
背景:(非常粗略)
当您定义
RowDefinition
的高度时,可能会发生三种情况,具体取决于您使用的单位类型最终使用:Measure
的高度,然后传递element.DesiredSize.Height
作为Arrange
的高度。Measure
和Arrange
方法。相同的逻辑仅适用于有关宽度而不是高度的列定义。
因此,星形定义是“停止”元素,像素定义也是“停止”,但它可以在渲染视图之外,而自动定义是“让”元素成为它想要的任何大小。
所有这些逻辑都是递归的,因此您需要从两个方向思考(解释如下)。
就你的情况
朝一个方向。
ListBox
位于星形行中,因此它将被停止。父网格也被停止(因为扩展器的模板使用也是“停止面板”的 DockPanel)。扩展器被定义为从星形行开始,但它跨越到自动行 - 这意味着它将允许其高度增长“直到无穷大”。哎呀……是时候逆转了。现在反方向。扩展器没有停止,子网格没有停止(因为网格假设它有无限的可用高度),因此列表框没有停止,列表框模板中的
ScrollViewer
没有停止所以它的 ViewportHeight 是无限的,对于排列项目(并且是滚动查看器的子级)的 VirtualizingStackPanel 来说,这意味着所有项目都在视图中 == 渲染所有元素。对于具有默认模板的 WPF 窗口,您始终可以假设该窗口正在停止其子元素。因此,如果删除行跨度定义未能解决问题,请继续向上遍历,直到找到另一个不阻止其子高度的元素并更改其定义或更改面板以阻止高度增长到无穷大(滚动查看器因创建这些行为,尤其是隐藏在模板中的行为)。
Short version: remove
Grid.RowSpan
from the expander.Long version:
Background: (in really broad strokes)
When you define the height of
RowDefinition
three things can happen, depending what type of units you end up using:Measure
andArrange
methods of the element.Measure
and thenelement.DesiredSize.Height
forArrange
.Measure
andArrange
methods.Same logic is applied to column definitions only regarding width instead of height.
So, star definition is "stopping" the element, pixel definition is also "stopping" but it can be outside of the rendered view and auto definition is "letting" the element to be what ever size it wants to be.
All this logic is recursive so you need to think in two directions (explanation below).
In your case
In one direction. The
ListBox
is in a star row so it'll be stopped. The parent grid is also stopped (since the template for expander usesDockPanel
that is also a "stopping panel"). The expander is defined to begin in a star row but it spans to an auto row - this means that it will be allowed to grow in height 'till infinity. Oops...time to reverse.Now the reverse direction. The expander is not stopped, the child grid is not stopped (since the grid assumes it has infinite height available), thus the list box is not stopped, the
ScrollViewer
in the template of list box is not stopped so it'sViewportHeight
is infinite, for theVirtualizingStackPanel
that arranges the items (and is a child of the scroll viewer) this means all items are in the view == render all elements.For a WPF window with default template, you can always assume the window is stopping its child element. So if removing the row span definition has not resolved the issue, continue traversing up until you find another element that is not stopping its child height and change its definitions or change the panel to stop the height from growing to infinity (scroll viewers are notorious for creating these behaviours, especially the ones that are hidden in templates).