WPF ComboBox performance problems by binding a large collections

I'm trying to bind a large collection to a ComboBox and I faced performance problems when opening ComboBox's popup. I searched internet and found that using VirtualizingStackPanel as a items panel template might help, but it helped only partially. If I bind a large collection to a ComboBox, I could open popup very quickly, that's ok, but if after that I bind another collection to a ComboBox and try to open popup again, it becomes very slow. Same is happening if you open popup for an empty ComboBox, then bind large collection and try to open popup again - it takes some seconds before popup opens.

Here is the XAML:

<ComboBox Name="cbBlah">
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

and the sample code for binding to reproduce the problem:

var list = new List<string>();
for (var i = 0; i < new Random().Next(9000, 10000); i++)
    list.Add(i.ToString());
cbBlah.ItemsSource = list;

I tried to make virtualizing stack panel to look like this:

<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />

but it doesn't help, seems VirtualizationMode is ignored so popup opens very fast only first time and then, each time after binding changes, it's very slow.

UPDATE: I thought about not binding new collection every time, but bind an ObservableCollection once and then just changing its content. Same thing, as soon as content of collection changes, opening a popup still takes several seconds :(


Solution 1:

According to this blog: http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx

I've tested it with this code:

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

It works fine for first time and next times. It's not necessary to code these lines:

<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />

I hope this helps you.

Solution 2:

I had the issue with slow performance as well. But I had created a class that inherited form Combobox, therefor I would like to do this programmatically. So here is that solution for other googlers out there.

ItemsPanel = new ItemsPanelTemplate();
var stackPanelTemplate = new FrameworkElementFactory(typeof (VirtualizingStackPanel));
ItemsPanel.VisualTree = stackPanelTemplate;