WPF Controls and Virtualization

Some of the built-in WPF control can be virtualized and some are virtualized by default. See Optimizing Performance: Controls.

I’m working on migrating a WinForm application to WPF, in doing so I happily recreated the code to load a ComboBox with a fairly large amount of data from a web service call. In the Windows Forms ComboBox this seemed to be have fairly good performance. Not so in the WPF ComboBox!

Some WPF controls, such as the ComboBox create their list control/dropdown to accommodate all items, therefore all items are rendered to the popup associated with it. It then uses a ScrollViewer to handle the scrolling of this large view object. Obviously when we’re talking about something like 10,000+ items (as I’m populating it with), clicking the dropdown button results in a very slow display of the associated popup whilst it’s busy rendering non-visible items.

What would be preferably is if we could load only the items to fit the dropdown space into the popup and have the scrollbar “think” that there’s more data, then we can “virtualize” our loading of data into the UI control.

We do this using the following code

<ComboBox ItemsSource="{Binding}">
   <ComboBox.ItemsPanel>
      <ItemsPanelTemplate>
         <VirtualizingStackPanel />
      </ItemsPanelTemplate>
   </ComboBox.ItemsPanel>
</ComboBox>

Other ItemsControl objects

In the case of the WPF ListView and ListBox, both are virtualized by default.

However, to paraphrase “Optimizing Performance: Controls”

By default WPF ListBoxes use UI virtualization when used with databinding, however if you add ListBoxItem’s explicitly the ListBox does not virtualize.

The TreeView can be enabled using the following code

<TreeView ItemsSource={Binding} VirtualizingStackPanel.IsVirtualizing="True" />

The ContextMenu can also be virtualized.

Scrolling

We might find that an ItemsControl, for example a ListBox, is slow when scrolling. In this case we can use the attached property VirtualizingStackPanel.VirtualizationMode as per

<ListBox ItemsSource={Binding} VirtualizingStackPanel.VirtualizationMode="Recycling" />