none
Virtualizing RRS feed

  • Question

  • I'd like to use the VirtualizedStackPanel to display almost 3000 rows of data.  Please see code below.  My hope was that since the only controls created were the first few rows that show on the screen the virtualizing panel would return quickly after the 3000 rows were bound to it.

    In the code below, it does not seem to matter if I set my ListView's VirtualizingStackPanel.IsVirtualizing to True or False, it still takes about 15 seconds to bind the data.  This is actually blazing fast compared to WinForms which could never even do this, but I wonder if vitualizing is really working, because it does not seem to be affecting the time it takes to display the control after binding the data.  Are my assumptions about the effects of virtualizing incorrect, or do I need to do something different to enable it?

    thx.

    Matt

     

     

    <Window xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' Width="664.8"
            x:Class="SDKSample.Window1">
      <Window.Resources>
        <XmlDataProvider  x:Key="MyData" XPath="/Info">
          <x:XData>
            <Info xmlns="">
              <Item ID="12345" Name="Book 1" Price="$32.05"
                    Author="Author A" Catalog="Business">
               
                <PublishDate date="10/15/2001" />
                <PublishDate date="10/15/2003" />
                <PublishDate date="10/15/2004" />
                <PublishDate date="10/15/2005" />
               
              </Item>
                <Item ID="13590" Name="Book 2" Price="$10.00"
                    Author="Author B" Catalog="Language"/>

              <Item ID="24678" Name="Book 3" Price="$9.00"
                    Author="Author C" Catalog="Language"/>
              <Item ID="65432" Name="Book 4" Price="$8.50"
                    Author="Author D" Catalog="Business"/>
              <Item ID="11233" Name="Book 5" Price="$19.00"
                    Author="Author E" Catalog="Health"/>
              <Item ID="94837" Name="Book 6" Price="$8.50"
                    Author="Author F" Catalog="Language"/>
            </Info>
          </x:XData>
        </XmlDataProvider>
        <CollectionViewSource x:Key='src'
                              Source="{Binding Source={StaticResource MyData},
                                       XPath=Item}">
          <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="@Catalog" />
          </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
      </Window.Resources>
      <ScrollViewer>
        <StackPanel>

          <Button Click="GetData" Content="Load XML"/>

          <ListView Name="lview" ItemsSource='{Binding Source={StaticResource src}}'
                  BorderThickness="0" VirtualizingStackPanel.IsVirtualizing="True" >
          <ListView.GroupStyle>
            <GroupStyle>
              <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                  <Setter Property="Margin" Value="0,0,0,5"/>
                  <Setter Property="Template">
                    <Setter.Value>
                      <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander IsExpanded="True" BorderBrush="#FFA4B97F"
                                  BorderThickness="0,0,0,1">
                          <Expander.Header>
                            <DockPanel>
                              <TextBlock FontWeight="Bold" Text="{Binding Path=Name}"
                                         Margin="5,0,0,0" />

                              <TextBlock FontWeight="Bold" Text=" Count: "
                                         Margin="5,0,0,0" />

                              <TextBlock FontWeight="Bold"
                                         Text="{Binding Path=ItemCount}"/>
                            </DockPanel>
                          </Expander.Header>
                          <Expander.Content>
                            <ItemsPresenter />
                          </Expander.Content>
                        </Expander>
                      </ControlTemplate>
                    </Setter.Value>
                  </Setter>
                </Style>
              </GroupStyle.ContainerStyle>
            </GroupStyle>
          </ListView.GroupStyle>
          <ListView.View>
            <GridView>
              <GridViewColumn Header="ID"
                              DisplayMemberBinding="{Binding XPath=@ID}"
                              Width="100" />
              <GridViewColumn Header="Name"
                              DisplayMemberBinding="{Binding XPath=@Name}"
                              Width="140" />
              <GridViewColumn Header="Price"
                              DisplayMemberBinding="{Binding XPath=@Price}"
                              Width="80" />
              <GridViewColumn Header="Author"
                              DisplayMemberBinding="{Binding XPath=@Author}"
                              Width="80" />
              <GridViewColumn Header="PublishDate"
                           
                           
                              Width="80" >
                <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <ListBox ItemsSource="{Binding XPath=PublishDate}">
                      <ListBox.ItemTemplate>
                        <DataTemplate>
                          <TextBlock Text ="{Binding XPath=@date}"/>
                        </DataTemplate>
                      </ListBox.ItemTemplate>
                    </ListBox>
                  </DataTemplate>
                </GridViewColumn.CellTemplate>
              </GridViewColumn>
            </GridView>
          </ListView.View>
        </ListView>


        </StackPanel>
      </ScrollViewer>
    </Window>

     

    Wednesday, November 15, 2006 5:59 PM

Answers

  • I see that you're using Grouping in the ListView.  Unfortunately the ListView doesn't use a virtualizing panel when it's grouped, it uses a plain old StackPanel.  That explains why it's taking so long.  Hopefully v2 will have that issue resolved.
    Wednesday, November 15, 2006 7:01 PM
  • A sad answer: we don't support grouping + virtualization.

    Handling the virtualization of groups is a gnarly problem and we wanted to get it right or not do it at all...we ended up not doing it at all.

    Friday, November 17, 2006 7:32 AM
  • DanCre posted a series of articles about building a Virtualizing Panel (I link to them all from here - http://blogs.msdn.com/okoboji/archive/2006/07/25/678403.aspx)

    Keep in mind, when we designed our virtualizing support, we didn't have grouping in mind. I'm not 100% sure it's possible to build with the API we expose (since ItemsControl does special work when generating groups over a CollectionView).

    Please let me know about your success.

    Sunday, November 19, 2006 6:14 AM

All replies

  • I see that you're using Grouping in the ListView.  Unfortunately the ListView doesn't use a virtualizing panel when it's grouped, it uses a plain old StackPanel.  That explains why it's taking so long.  Hopefully v2 will have that issue resolved.
    Wednesday, November 15, 2006 7:01 PM
  • Thanks Josh.  I would have spent hours beating my head on this and then given up.

    Just to make sure I understand this stuff, I took out the Grouping.  I'm still seeing the same behavior I described above: 12-15 secs to show the window independent of what VirtualizingStackPanel.IsVirtualizing is set to.  Is this what would be expected from the code below?

     

     

    <Window xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' Width="664.8"
            x:Class="SDKSample.Window1">
      <Window.Resources>
        <XmlDataProvider  x:Key="MyData" XPath="/Info">
          <x:XData>
            <Info xmlns="">
              <Item ID="12345" Name="Book 1" Price="$32.05"
                    Author="Author A" Catalog="Business">
               
                <PublishDate date="10/15/2001" />
                <PublishDate date="10/15/2003" />
                <PublishDate date="10/15/2004" />
                <PublishDate date="10/15/2005" />
               
              </Item>
                <Item ID="13590" Name="Book 2" Price="$10.00"
                    Author="Author B" Catalog="Language"/>

              <Item ID="24678" Name="Book 3" Price="$9.00"
                    Author="Author C" Catalog="Language"/>
              <Item ID="65432" Name="Book 4" Price="$8.50"
                    Author="Author D" Catalog="Business"/>
              <Item ID="11233" Name="Book 5" Price="$19.00"
                    Author="Author E" Catalog="Health"/>
              <Item ID="94837" Name="Book 6" Price="$8.50"
                    Author="Author F" Catalog="Language"/>
            </Info>
          </x:XData>
        </XmlDataProvider>
        <CollectionViewSource x:Key='src'
                              Source="{Binding Source={StaticResource MyData},
                                       XPath=Item}">
         
        </CollectionViewSource>
      </Window.Resources>
      <ScrollViewer>
        <StackPanel>

          <Button Click="GetData" Content="Load XML"/>

          <ListView Name="lview" ItemsSource='{Binding Source={StaticResource src}}'
                  BorderThickness="0" VirtualizingStackPanel.IsVirtualizing="False" >
          <!--<ListView.GroupStyle>
            <GroupStyle>
              <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                  <Setter Property="Margin" Value="0,0,0,5"/>
                  <Setter Property="Template">
                    <Setter.Value>
                      <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander IsExpanded="True" BorderBrush="#FFA4B97F"
                                  BorderThickness="0,0,0,1">
                          <Expander.Header>
                            <DockPanel>
                              <TextBlock FontWeight="Bold" Text="{Binding Path=Name}"
                                         Margin="5,0,0,0" />

                              <TextBlock FontWeight="Bold" Text=" Count: "
                                         Margin="5,0,0,0" />

                              <TextBlock FontWeight="Bold"
                                         Text="{Binding Path=ItemCount}"/>
                            </DockPanel>
                          </Expander.Header>
                          <Expander.Content>
                            <ItemsPresenter />
                          </Expander.Content>
                        </Expander>
                      </ControlTemplate>
                    </Setter.Value>
                  </Setter>
                </Style>
              </GroupStyle.ContainerStyle>
            </GroupStyle>
          </ListView.GroupStyle>-->
          <ListView.View>
            <GridView>
              <GridViewColumn Header="ID"
                               DisplayMemberBinding="{Binding XPath=@ID}"
                              Width="100" />
              <GridViewColumn Header="Name"
                            
                              Width="140" >
                <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <Button Content="{Binding XPath=@Name}"/>
                  </DataTemplate>

                </GridViewColumn.CellTemplate>
              </GridViewColumn>
              <GridViewColumn Header="Price"
                              DisplayMemberBinding="{Binding XPath=@Price}"
                              Width="80" />
              <GridViewColumn Header="Author"
                              DisplayMemberBinding="{Binding XPath=@Author}"
                              Width="80" />
              <GridViewColumn Header="PublishDate"
                           
                           
                              Width="80" >
                <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <ListView ItemsSource="{Binding XPath=PublishDate}">
                      <ListView.ItemTemplate>
                        <DataTemplate>
                          <TextBlock Text ="{Binding XPath=@date}"/>
                        </DataTemplate>
                      </ListView.ItemTemplate>
                    </ListView>
                  </DataTemplate>
                </GridViewColumn.CellTemplate>
              </GridViewColumn>
            </GridView>
          </ListView.View>
        </ListView>


        </StackPanel>
      </ScrollViewer>
    </Window>

    \

     

    Wednesday, November 15, 2006 7:40 PM
  • Wednesday, November 15, 2006 8:51 PM
  • Thanks Josh.

    That does not seem to work.  I tried setting the CanContentScroll property to true and removing the ScrollViewer completely.  Neither seems to help.  I also tried removing the PublishDate column on a hunch that the variable length rows might be messing up things. That did not seem to help either.

    Any other ideas? Is there any way to attach a zip file to these posts?

    thx. 

    Wednesday, November 15, 2006 10:01 PM
  • A sad answer: we don't support grouping + virtualization.

    Handling the virtualization of groups is a gnarly problem and we wanted to get it right or not do it at all...we ended up not doing it at all.

    Friday, November 17, 2006 7:32 AM
  • Hi Matt, I have a pretty little hypothesis to "correct" your problem...

       Looking at your XAML, I can see that you ListView is placed within a StackPanel that is itself placed inside a ScrollViewer...

       As you might know, the job of a ScrollViewer is to allow its child to layout at its maximum possible size; therefore, in the measure pass, it provides your StackPanel with an Infinite size...

       Since the StackPanel is passed an infinite size, it also allows its childs to take as much space as they want... Therefore, your ListView is probably taking all the space nescessary to layout ALL its children... therefore, no virtualization is done (here goes your 15 seconds)...

       Try removing the top level ScrollViewer, or in fact, ensure that your ListView will not be passed "Infinity" in its measure pass... And you should see a great optimization in the loading time...

       While Kevin is right ( grouping + virtualization do not like each other), if you disable grouping and perform this... You should regain most of your performance...
    Friday, November 17, 2006 1:58 PM
  • Thanks for all the help everyone. 

    One more question for Kevin. 

    Can you talk about any plans to support groups in the future?  Its not clear if you gave up all together, or just for v1.

     

    thx.

     

    Friday, November 17, 2006 3:59 PM
  • We have no hard plans.

    We know it's important for a lot of people, but lot's of things are important to lots of people :-)

    There is no reason that it's can't be built (by us or a 3rd-party). It's a question of how we prioritize.

    At this point, I can't offer much more than that.

    Friday, November 17, 2006 7:19 PM
  • Thanks Kevin.  It would be great if you could point me to any information on Virtualizing that could help me implement this myself.   Is it simply a matter of implementing an interface in ListView, or would I have to recreate the entire control from scratch?  There does not seem to be much info on the guts of Virtualizing in the docs.  Any blog posts our other info you could point me to?

     

    thx.

     

    Matt

     

    Sunday, November 19, 2006 2:33 AM
  • DanCre posted a series of articles about building a Virtualizing Panel (I link to them all from here - http://blogs.msdn.com/okoboji/archive/2006/07/25/678403.aspx)

    Keep in mind, when we designed our virtualizing support, we didn't have grouping in mind. I'm not 100% sure it's possible to build with the API we expose (since ItemsControl does special work when generating groups over a CollectionView).

    Please let me know about your success.

    Sunday, November 19, 2006 6:14 AM
  • Is Microsoft working on fixing Virtualization for various panels ?
    Can we expect to have virtualization working for all kind of panels (wrapPanel, group,...) and grouping ?

    Because without it, we need to workaround and that removes a lot of interest to WPF...

    Thanks !

    Wednesday, April 30, 2008 7:45 AM
  • Sorry to drag up an old thread, however has this been resolved for WPF 4.0 ?  I am trying to load a large amount of data into a ListBox that is grouped and has an expander to collapse the group.

    I still haven't found a good solution that allows me to collapse the groups.
    Tuesday, October 27, 2009 10:02 AM