VirtualizingStackPanel无法正确处理已折叠的项

3

我在wpf中使用ListView显示字段列表,根据属性值,一些字段可以在运行时折叠。它的工作正常,除了ListView不会在运行时折叠 ListViewItem 时收缩保留的空间。

enter image description here

我能够在Snoop中看到额外的ListViewItems(可见性为Collapsed),ListView也将项目向上移动,但它不会调整其高度以删除空白空间!

我可以肯定地说,这是由于VirtualizedStackPanel导致的,将ItemsPanel更改为StackPanel可以解决此问题。以下是相关的ListView XAML:

<ListView
    x:Class="Wizards.FieldBinderModelListView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Margin="0"
    VerticalAlignment="Top"
    HorizontalContentAlignment="Stretch"
    VerticalContentAlignment="Top"
    Background="White"
    BorderThickness="0"
    Grid.IsSharedSizeScope="True"
    KeyboardNavigation.DirectionalNavigation="Continue"
    Padding="1"
    ScrollViewer.HorizontalScrollBarVisibility="Hidden"
    ScrollViewer.VerticalScrollBarVisibility="Hidden"
    SelectionChanged="ListViewSelectionChanged"
    SelectionMode="Single">
    <ListView.ItemsPanel>
       <ItemsPanelTemplate>
        <!--Works fine with StackPanel but not with VirtualizingStackPanel
          Explicitly added this PanelTemplate to show that it works with            
          StackPanel;ListView uses VirtualizingStackPanel as default panel 
          and causes same problem-->              
        <!--<StackPanel Orientation="Vertical" VerticalAlignment="Top"/>-->
          <VirtualizingStackPanel Orientation="Vertical" 
               VerticalAlignment="Top"/>
       </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemContainerStyle>
      <Style TargetType="{x:Type ListViewItem}">
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="Foreground" Value="Black" />
            </Trigger>
            <DataTrigger Binding="{Binding Status}"
                         Value="{x:Static local:Status.NotExisting}">
                <!--Hide the fields which are in NotExisting state; 
                  Need a trigger here as Status can be different -->
                <Setter Property="Visibility" Value="Collapsed" />
            </DataTrigger>
        </Style.Triggers>
      </Style>
  </ListView.ItemContainerStyle>
  <ListView.ItemTemplate>
    <DataTemplate DataType="{x:Type View:FieldViewModel}">
       <local:FieldEditor
          Margin="0,2,0,0"
          HorizontalAlignment="Stretch"
          VerticalAlignment="Top"
          HorizontalContentAlignment="Stretch"
          VerticalContentAlignment="Top"
          Padding="0">
          <!--<local:FieldEditor.Style>
              <Style TargetType="{x:Type local:FieldEditor}">
                <Style.Triggers>
                  <DataTrigger
                    Binding="{Binding Status}"
                    Value="{x:Static local:Status.NotExisting}">
                      <Setter Property="Visibility" Value="Collapsed" />
                  </DataTrigger>
                </Style.Triggers>
              </Style>
            </local:FieldEditor.Style>-->
        </local:FieldEditor>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

这是VirtualizingStackPanel的一个bug吗?有其他人遇到过类似的问题吗?是否有解决方法?
更新: 已向微软报告了此错误- https://connect.microsoft.com/VisualStudio/feedback/details/734113/virtualizingstackpanel-not-handling-collapsed-items-correctly

请发布您折叠某些项目的代码。为什么虚拟化列表上会有一个隐藏的垂直滚动条? - paparazzo
感谢BalamBalam,我已经更新了带有相关XAML的帖子;滚动条被隐藏了,因为此列表视图添加到将处理滚动的父ListView中,可以在父列表视图中存在多个此ListView和其他控件;虽然启用它们并不会改变这种行为。 - akjoshi
虚拟化控件不仅仅是使用VirtualizingStackPanel,ListView默认情况下也是虚拟化的。 - Rachel
好的,假设我启用滚动,这会解决我面临的问题吗?不,我已经尝试过了,无论滚动条启用/禁用,空白空间仍然存在。 - akjoshi
谢谢BalamBalam,我的意图并不是冒犯你;我发表了那条评论是为了让大家知道我已经尝试过了(正如我在第一条评论中提到的),即使虚拟化被禁用,ListView也不应该表现出这种方式! - akjoshi
显示剩余2条评论
2个回答

6

我成功地复现了你的问题。这显然是VirtualizingStackPanel中的一个bug。 一种解决方法是将隐藏项的高度设置为零而不是折叠它们:

<DataTrigger Binding="{Binding Status}" Value="False">
    <Setter Property="Height" Value="0" />
    <Setter Property="IsEnabled" Value="False"/>
    <!--<Setter Property="Visibility" Value="Collapsed" />-->
</DataTrigger>

谢谢Phil,将高度设置为0解决了问题,但我仍然好奇为什么将可见性设置为Collapsed没有起作用! - akjoshi
很遗憾我没有得到赏金 :-( - Phil
是的,我同意,我离开办公室几天,没有能够查看你的答案。对此感到抱歉。 - akjoshi

2

如果其他人也想继续依赖Visibility但又想去除额外的间距,可以通过删除ListBoxItem样式中的Padding来解决:

<ListBox.ItemContainerStyle>
    <Style TargetType="ListBoxItem">
        <Setter Property="Padding" Value="0"/>
    </Style>
</ListBox.ItemContainerStyle>

看起来ListBoxItem的默认填充为3。


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