3

I have a ComboBox which when I repopulate it, it seems to be quite a time consuming task. After doing some profiling I have found that the majority of the time is spent in the ComboBox.Items.AddRange(Array) method. I have included an example method below which shows how I carryout the repopulating of the ComboBox.

public void Repopulate(IList<MyType> sortedList)
{
    MyComboBox.BeginUpdate();

    try
    {
        MyComboBox.Items.Clear();
        MyComboBox.Items.AddRange(sortedList.ToArray());
    }
    finally
    {
        MyComboBox.EndUpdate();
    }
}

sortedList contains around 280 items, and there are up to 53 ComboBox's which need to be repopulated. So it can take quite some time to repopulated all these controls (approx. 700ms on a high spec machine, 8000ms on a low spec machine) which is too slow for my requirements. I tried adding the sortedList to a new IList and that took around 1ms (on my high spec machine).

I need to get the repopulating of the ComboBox so that it takes significantly less time, ideally similar times to the IList but any performance increase would be good. So far I have been unable to find any way to improve the speed of the re-population.

Does anyone have any idea's on how I can reduce the time taken to re-populate the ComboBox?

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
dante671
  • 117
  • 1
  • 10
  • 1
    Tried using virtualized controls instead? That way you wouldn't have to supply all the data at once. – Simon May 16 '12 at 11:35
  • Also, are you handling the AddRange calls sequentially? Meaning that you call AddRange on the first, and then the second, up to 53? – Joshua Drake May 16 '12 at 12:53
  • @Simon I haven't came across virtualised controls before, and I can't seem to find anything about them on Google/MSDN. Do you happen to know a good source for information about them? – dante671 May 16 '12 at 13:02
  • @JoshuaDrake Yes that's pretty much exactly what I am doing. I repopulate one ComboBox then move onto the next, until all 53 have been repopulated. – dante671 May 16 '12 at 13:05
  • Could you thread out the populating of the boxes in some way? It would certainly speed up the aggregate load time. – Joshua Drake May 16 '12 at 13:09
  • @dante671 I think that data virtualisation might only be available for WPF at the moment. You add attributes to instruct the control to only fetch the data that is visible at any time (IsVirtualizing="True"). – paul May 16 '12 at 13:10
  • 1
    @dante671 but really, if you are putting 280 items in a combobox for your users to scroll through then you might find it better (for your users) to approach the situation differently, i.e. an autocomplete textbox – paul May 16 '12 at 13:11
  • I am also curious why you are reloading them every time, does the data change? – Joshua Drake May 16 '12 at 13:37
  • @JoshuaDrake Yes the data changes quite often, new items are added, existing items removed etc. In this case it's in response to the User clicking a CheckBox which applies a filter to the data. That filter could be different for each of the ComboBox's – dante671 May 16 '12 at 13:51
  • any final solution with full source code sample working about it ? – Kiquenet Nov 05 '13 at 09:34

4 Answers4

1

Your problem could be that you have enabled the combobox's Sorted property. When this is enabled and you call AddRange the combobox sorts all those items, which if your items are already sorted, is unnecessary.

To prove my point, I created two combobox's that were populated using 10,000 sorted ints and AddRange. The only difference was that one combobox had the Sorted property enabled, the other one didn't. Here are the times in milliseconds of the resulting AddRange call

notSortedCombo: 5ms
sortedCombo: 1140ms

Could this be your problem? Could you have 53 comboboxes that have the sorted property enabled?

Nick Babcock
  • 6,111
  • 3
  • 27
  • 43
  • I have checked this and the Sorted property is set to false so unfortunately that won't be the cause of the problem – dante671 May 16 '12 at 13:27
1

AddRange already calls BeginUpdate and EndUpdate under the hood, so you aren't gaining anything by calling it yourself.

This shaved a few milliseconds off of it for me:

public void Repopulate(IList<string> sortedList) {
  comboBox1.BeginUpdate();
  comboBox1.Items.Clear();
  foreach (string item in sortedList) {
    comboBox1.Items.Add(item);
  }
  comboBox1.EndUpdate();
}

The bigger problem is probably the design: 53 combo boxes is a lot of combo boxes to throw at a user — the user won't be able to interact with all 53 controls at once. You could get a little hacky and just populate the combo boxes with the visible value (1 item) and then populate the list as the control gets focused or in a background timer.

But consider reducing the number of controls on the screen. White space is considered a good thing.

LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • Thanks I will remove the BeginUpdate and EndUpdate calls. Unfortunately the number of control's can't really be reduced, the initial number of ComboBox's starts off low but the User has the option of adding additional controls based on their requirements (53 is the maximum number of ComboBox's that will ever exist on the form). – dante671 May 16 '12 at 13:55
  • @dante671 Then just load the combo boxes as the user is adding them, that is, only load them when needed. – LarsTech May 16 '12 at 14:02
0

Regarding UI virtualization: Virtualization exists both for WPF (Example) and WinForms. But only some controls support it, like ListView, DataGridView, TreeView, etc. Those are the controls designed for bigger amounts of data. If possible you could switch to one of these controls.

Are all controls visible on screen at the same time? Maybe only updating the visible ones will help.

An alternative is to update the combo boxes asynchronously. If you're lucky enough to work with the new async/await stuff in .NET this is easily done. If you want to do it manually, you can just update a single combobox and schedule the update of the next combobox a few milliseconds in the future (use a timer or the TPL). This way the UI is at least still responsive while the update takes place.

Yet another way is to update the list only when the user focusses a certain ComboBox. There's usually no need to update the contents because the user will only see it when he uses the ComboBox.

You could also try to hide the combobox before you update its data. Or you could tell windows not to redraw the UI while modifying the contents (StackOverflow topic here). But I haven't tested whether this really improves the performance.

Simon
  • 1,814
  • 20
  • 37
0

You can improve performance by changing property FormattingEnabled of your combobox to False

The problem is that Visual Studio keeps it as True if you don't specify items "manually" in the designer, but add them programmatically.

Try, it solved issue for me

romandrahan
  • 109
  • 6