Hi

 

In my latest article I discussed Scrolling and Binding to large collections in WPF. We saw some disturbing behavior when binding a large collection to an ItemsControl. After Further Examination I found out very interesting things regarding that matter.

 

Memory Consumption

 

We saw that the application used about 500MB of Ram. Lets look at the code again:

   1: <ScrollViewer CanContentScroll="True">  
   2:     <ItemsControl ItemsSource="{Binding}" >              
   3:          </ItemsControl>  
   4: </ScrollViewer>

What happens here is that because the ItemsControl has not Height Definition he grows to the size it needs in order to show ALL the items (50K in that application) making all of them drawn but not shown.The ScrollViewer gives you the option to scroll because the ItemsControl is much larger then him (he is restricted to the window size).

The correct way to implement this is the following:

   1: <ItemsControl ItemsSource="{Binding}" ScrollViewer.CanContentScroll="True"
   2:               Height="300" Width="160" 
   3:               ScrollViewer.VerticalScrollBarVisibility="Visible" >
   4: </ItemsControl>

The problem is that IT DOES NOT WORK!!! you will never get a ScroollBar this way, which brings me to my second point

 

Why the ItemsControl.ScrollViewer is Useless

 

After looking at the ItemsControl Template I realized why it just does not work, There is no ScrollViewer in the Template! This is the template:

 

   1: <ControlTemplate TargetType="ItemsControl" 
   2:                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
   3:     <Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
   4:           Padding="{TemplateBinding Control.Padding}" 
   5:           BorderBrush="{TemplateBinding Border.BorderBrush}" 
   6:           Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
   7:       <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}">
   8:       </ItemsPresenter > 
   9:   </Border>
  10: </ControlTemplate>

Do you see a ScrollViewer? I don’t, therefore it will not work. God and Microsoft only knows why that property Exists, more on that matter in a different post, for now, lets solve this issue.

 

Changing the ItemsControl to a ListBox

 

Once I changed the ItemsControl to a ListBox everything worked like a charm. This is the Code:

   1: <ListBox ItemsSource="{Binding}" ScrollViewer.CanContentScroll="True"
   2:          ScrollViewer.VerticalScrollBarVisibility="Visible" >
   3: </ListBox>

Here is the same image as in the first article:

ItemsControl Scrolling

 

Same amount of Objects, only 23MB of ram! We went from 500MB to 23MB and we just changed from ItemsControl to ListBox. WOW.

 

For the moment I think this is the best solution If you have a large amount of items, use a ListBox. And If you want to eliminate the selection just create a template for the selected items that makes him look as a regular one and that’s it.

 

Amit

Tags :

9 Responses to “Why the ItemsControl ScrollViewer Attached Property Does Not Work”


  1. Paul

    Said on February 9, 2009 :

    We have an application that’s currently displaying a large number of items in a WPF treeview. We originally had the items as treenodes, but then changed it so that the treenode was a listbox for performance reasons.

    What we found was that validation for non-visible items in the listbox wasn’t firing until they were scrolled into view. Ultimately, we wound up going back to the treenode version, because the large number of items was an edge condition and getting validation fired was more important than occassional performance.

    Could the change in memory usage be because WPF isn’t “creating” the items in the listbox until they come into view? If this is the case, then the memory savings is only temporary — once the user scrolls the list to the bottom, the memory will be used again. But it would still be beneficial if scrolling through all the items in the list was an atypical action, because you’d only use the extra memory if necessary.

    Just a thought.

    Paul

  2. Amit

    Said on February 10, 2009 :

    Hi Paul

    I Actually think that the WPF “Drawing Algorithm” is smarter. Because there is almost no change in the Memory consumption while you scroll all the way down (50K items) I think that he calculates how many objects appear on screen, creates them (and maybe some more on each end to make scrolling smooth) and then only switches the data between them.

    Once I have time I will check this out using reflector.

    Amit

  3. Paul

    Said on February 10, 2009 :

    Well that’s good to know. We may go back and take a look at it if we find time to move our validation notification to the business objects so we don’t have to rely on the UI events. We can probably use the memory savings to justify the work.

    Cool article, thanks!

  4. Benjamin

    Said on February 10, 2009 :

    Great tip!

    You should write more often ;)

  5. Amit

    Said on February 10, 2009 :

    @ Benjamin

    We are very busy, but we are trying. :)

  6. Caleb

    Said on February 12, 2009 :

    I don’t think that you understand what the ScrollViewer.CanContentScroll option is doing. Setting it to true means that if the child element (to the ScrollViewer) implements IScrollInfo then the ScrollViewer will delegate to that interface to do the scrolling. If you had set the items control’s ItemsPanel to a virtualizing stack panel in the original snipet I think you would have gotten a similar result.

  7. Amit

    Said on February 12, 2009 :

    @ Caleb

    Sorry, no go, Just tried it. I dont see how it will work when ItemsControl control template has no ScrollViewer in it…

    Amit

  8. Nithya

    Said on December 29, 2010 :

    HorizontalOffSet,VerticalOffSet Attach property is not working by using MVVM.

  9. SpeakingStones

    Said on August 3, 2011 :

    This is a clearly points out Wpf is a over engineered piece of marketing fancy. It is so easy to produce incredibly resource hungry screens by following the standard patterns. The designers of Wpf should be ashamed. Even Microsoft gets this now hence it is dead.

Post a Comment