我有一个ListView元素,每个ListViewItem都有一个DataTemplate,定义如下。运行时,ListView的高度不会折叠到视图中的项目上,这是不良行为:

<DataTemplate x:Key="LicenseItemTemplate">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"  />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="{Binding company}"></TextBlock>
        <Grid Grid.Row="1" Style="{StaticResource HiddenWhenNotSelectedStyle}">
            <Grid.RowDefinitions>
                <RowDefinition />
            </Grid.RowDefinitions>
            <Button Grid.Row="0">ClickIt</Button>
        </Grid>
    </Grid>
</DataTemplate>


外部网格的第二行应用了样式,如下所示。样式的目的是公开所选数据项的详细视图:

<Style TargetType="{x:Type Grid}" x:Key="HiddenWhenNotSelectedStyle" >
    <Style.Triggers>
        <DataTrigger
            Binding="{Binding Path=IsSelected,
                        RelativeSource={
                        RelativeSource
                        Mode=FindAncestor,
                        AncestorType={x:Type ListViewItem}
                        }
                        }"
            Value="False">
            <Setter Property="Grid.Visibility" Value="Collapsed" />
        </DataTrigger>
        <DataTrigger
            Binding="{Binding Path=IsSelected,
                        RelativeSource={
                        RelativeSource
                        Mode=FindAncestor,
                        AncestorType={x:Type ListViewItem}
                        }
                        }"
            Value="True">
            <Setter
                Property="Grid.Visibility"
                Value="Visible"
            />
        </DataTrigger>
    </Style.Triggers>
</Style>


ListView呈现如下:


当未选择任何元素时,所需的外观是这样的:


...当然,通过选择使第二个网格可见时,ListView的高度可以进行调整以容纳其他内容。我该怎么做才能达到预期的行为?

最佳答案

在TechEd与WPF人员讨论问题时,我向Microsoft员工展示了这个问题。他不高兴。

我们下载了一个查询WPF布局的工具,并将该容器标识为ListView中的“虚拟化堆栈面板”元素。

他在一封后续电子邮件中写道:“这是VirtualizingStackPanel的错。我已经打开了一个bug。希望它可以在以后的版本中修复。暂时的解决方法(使用StackPanel)应该可以了,只要您不需要ListView虚拟化其内容。

该错误涉及VSP的Measure算法中的一个步骤,该步骤会记住有史以来发现的最大大小,并强制所有以后的Measure调用报告至少一个大小。在您的情况下,VSP最初是在触发任何触发器之前进行测量的,因此它会像查看所有可见内容一样计算大小。当触发器触发并合拢按钮时,度量算法会计算正确的(小)尺寸,但随后会迫使结果再次变大。该评论说明了如何避免在滚动时不必要的重新布局,但是即使没有滚动,代码仍在运行。”

解决方法是使用以下代码重新模板化ListView:

<ListView.ItemsPanel>
  <ItemsPanelTemplate>
    <StackPanel/>
  </ItemsPanelTemplate>
</ListView.ItemsPanel>


这导致列表行为按预期工作,但是它具有不具有VirtualizingStackPanel的内存管理功能的缺点。就我而言,这是适当的;列表项永远不会超过2000个左右。

10-07 13:16
查看更多