0

I am working on a WPF Application where i have a combobox with ItemsSource binded to a property of 5000 records coming from database. The problem is that when i click the dropdown arrow of combobox the UI not responding or combobox is taking too much time to respond. I searched it but nothing worked for me.

here is the code:

 <ComboBox IsEditable="True" ItemsSource="{Binding List,Mode=OneWay}" DisplayMemberPath="name" SelectedValue="{Binding SelectedItem,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                                    <ComboBox.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />
                                        </ItemsPanelTemplate>
                                    </ComboBox.ItemsPanel>
                                </ComboBox>

and the property

  private ObservableCollection<Object> _List = new ObservableCollection<Object>();
        public ObservableCollection<Object> List
        {
            get { return _List ; }
            set { _List = value; OnPropertyChanged("List"); }
        }

Edit: here is the code that loads data inside the constructor

  public FormVM()
        {
              List = new ObservableCollection<Object>(db.cat.ToList());
        }
BionicCode
  • 1
  • 4
  • 28
  • 44
  • Please provide a "reproducible" problem. This code runs as fast as lightning. – Bizhan Jul 13 '20 at 12:54
  • Is the data loaded from the database in advance or in response to opening the combobox? We need to see the code that demonstrates the problem. – Emond Jul 13 '20 at 12:59
  • @Erno the data loaded from the database in advance. I loaded the data in constructor – Haris Aijaz Jul 13 '20 at 13:21
  • @Bizhan the code is running but UI is taking to much time to respond – Haris Aijaz Jul 13 '20 at 13:22
  • As I said, your problem is "not reproducible". So for us there is no problem. All is good. If I put a thread.sleep on the getter of `name` I will see what you explained, but without further info we can't help u – Bizhan Jul 13 '20 at 13:46
  • Anyways, you may want to read about different virtualizations: https://stackoverflow.com/q/1389769/366064 – Bizhan Jul 13 '20 at 13:57
  • btw, there is no point in setting the ObservableCollection like that. just use a regular list. or add to the ObservableCollection. – Bizhan Jul 13 '20 at 14:00
  • Please! please test your code once before posting in here! I still don't see anything wrong. is the db.cat.name a Func? is it lazy loaded? please do a little more research – Bizhan Jul 13 '20 at 14:13

1 Answers1

4

You have to enable UI virtualization.

Currently UI virtualization is disabled for your ComboBox!

Controls like ListBox or ListView have this feature enabled by default.
Other controls that extend ItemsControl like ComboBox have to enable it explicitly.

To enable UI virtualization

  1. The ItemsPresenter (or any Panel with Panel.IsItemsHost set to True) of the ItemsControl must be the child of a ScrollViewer.
    This is already the case for the ComboBox.

  2. The ScrollViewer must be configured to scroll by items (logical units) instead of pixels (physical units) by setting the attached ScrollViewer.CanContentScroll property to True.

  3. ItemsControl must have its ItemsPanel set to a VirtualizingStackPanel.

  4. The virtualization mode of the VirtualizingPanel must be enabled by setting the attached property VirtualizingPanel.IsVirtualizing to True.

Example

<ComboBox VirtualizingPanel.IsVirtualizing="True"
          ScrollViewer.CanContentScroll="True">
  <ComboBox.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel />
    </ItemsPanelTemplate>
  </ComboBox.ItemsPanel>
</ComboBox>

Further improvements can be achieved by enabling deferred scrolling:

<ComboBox ScrollViewer.IsDeferredScrollingEnabled="True" />

Satisfying one of the following conditions will make UI virtualization impossible:

  • Item containers are added directly to the ItemsControl. For example, if an application explicitly adds ListBoxItem objects to a ListBox, the ListBox does not virtualize the ListBoxItem objects.

  • Item containers in the ItemsControl are of different types. For example, a Menu that uses Separator objects cannot implement item recycling because the Menu contains objects of type Separator and MenuItem.

  • Setting CanContentScroll to false.

  • Setting IsVirtualizing to false.

If you have followed every constraint then UI virtualization does work. You then have a problem which is not related to UI virtualization. If yoou would set up a new empty project with just a ComboBox you should encounter no issues.

BionicCode
  • 1
  • 4
  • 28
  • 44
  • I can't thank you enough for this. I never would have thought "CanContentScroll" would affect the virtualization, since I was using the listview and it has already a built-in scrollview. – tataelm May 02 '22 at 20:44
  • @tataelm Thank you! The reason is that the panel must know when items leave/enter the viewport of the scroll viewer in order to be able to control container generalization/virtualization. Therefore, the panel needs logical scrolling (scroll by item). If you set `CanContentScroll` to `false`, you have physical scrolling (scroll by pixel). Scrolling vertically by "1" means: by 1 *item* when `CanContentScroll=true` or 1 *pixel* when `CanContentScroll=false`. Scrolling 1 *item* always means 1 item has become hidden/visible. But 1 pixel you can never know when an item becomes hidden/visible. – BionicCode May 02 '22 at 21:08