3

I am having a ListView in wpf which is used to display list of fields; based on a property value some of the fields can be collapsed at run time. Its working fine except that ListVIew does not collapse the space reserved for ListViewItem's which got collapsed at run time.

enter image description here

I am able to see the extra ListViewItems in Snoop(having Visibility as Collapsed), ListView too shifts the items upwards but it doesn't adjusts its height to remove the empty space!

I can surely say that this is happening due to VirtualizedStackPanel as changing the ItemsPanel to StackPanel solves the issue. Here is the relevant 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>

Is this a bug in VirtualizingStackPanel? Anyone else faced a similar issue? Any workarounds?


Update:

Reported this bug to MS on connect - https://connect.microsoft.com/VisualStudio/feedback/details/734113/virtualizingstackpanel-not-handling-collapsed-items-correctly

akjoshi
  • 15,374
  • 13
  • 103
  • 121
  • Please post the code where you collapse some items. Why a hidden vertical scroll bar on a virtualizing list? – paparazzo Feb 08 '12 at 13:59
  • Thanks BalamBalam, I have updated post with relevant xaml; Scrollbars are hidden as this list view is added into a parent ListView which will handle the scrolling, multiple instances of this ListView and other controls can be there in parent list view; although enabling them doesn't change this behavior. – akjoshi Feb 08 '12 at 14:39
  • [There's more to virtualizing a control than using a `VirtualizingStackPanel`](http://stackoverflow.com/a/2784220/302677), however I thought ListViews were Virtualized by default. – Rachel Feb 08 '12 at 17:37
  • I would look at the link in the above from @Rachel. If you are not going to enable the VerticalScroll bar on the individual ListView then I think you are going to break vitrualization as then the individual ListView thinks it has enough room for all items and as far as it know all its items on and the screen. I really doubt ListView can efficiently virtualize a whole ListView. A ListView cannot virtualize if the visual UI is not contrained. – paparazzo Feb 08 '12 at 21:49
  • Ok; Lets say I enable the scrolling, will this solve the problem I am facing...? No, I have tried that, empty space is still there irrespective of the scrollbar enabled/disabled. – akjoshi Feb 09 '12 at 04:39
  • It was posted as a comment. Sorry I tried to help. I had this problem once myself and I fixed it but I can't remember how and now I an not going to look. – paparazzo Feb 09 '12 at 19:30
  • Thanks BalamBalam, my intention was not to offend you; I posted that commment to let everyone know that I have already tried that(as mentioned in my first comment) and even if virtualization is disabled ListView should not behave this way! – akjoshi Feb 10 '12 at 04:57

2 Answers2

6

I managed to reproduce your problem. It certainly looks like a bug in VirtualizingStackPanel. A work around is to set the height of the hidden items to zero instead of collapsing them:

<DataTrigger Binding="{Binding Status}" Value="False">
    <Setter Property="Height" Value="0" />
    <Setter Property="IsEnabled" Value="False"/>
    <!--<Setter Property="Visibility" Value="Collapsed" />-->
</DataTrigger>
akjoshi
  • 15,374
  • 13
  • 103
  • 121
Phil
  • 42,255
  • 9
  • 100
  • 100
2

For anyone else looking for a way to continue relying on Visibility but also remove the extra spacing, I fixed it by removing the Padding in the style for the ListBoxItem:

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

It seems the ListBoxItem's default Padding is 3.