Подтвердить что ты не робот

Проблемы производительности WPF ComboBox путем привязки больших коллекций

Я пытаюсь связать большую коллекцию с ComboBox, и я столкнулся с проблемами производительности при открытии всплывающего окна ComboBox. Я искал интернет и обнаружил, что использование VirtualizationStackPanel в качестве шаблона панели элементов может помочь, но это помогло лишь частично. Если я привяжу большую коллекцию к ComboBox, я могу быстро открыть всплывающее окно, это нормально, но если после этого я привяжу другую коллекцию к ComboBox и снова попытаюсь открыть всплывающее окно, она станет очень медленной. То же самое происходит, если вы открываете всплывающее окно для пустого ComboBox, затем связываете большую коллекцию и снова пытаетесь открыть всплывающее окно - для всплывающего окна требуется несколько секунд.

Вот XAML:

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

и пример кода для связывания для воспроизведения проблемы:

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

Я попытался сделать панель виртуализации стека, чтобы она выглядела следующим образом:

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

но это не помогает, кажется, что VirtualizationMode игнорируется, поэтому всплывающее окно открывается очень быстро только в первый раз, а затем, каждый раз после привязки изменений, оно очень медленно.

UPDATE. Я думал о том, что не привязываю новую коллекцию каждый раз, но привязываю ObservableCollection один раз, а затем просто меняю ее содержимое. То же самое, как только содержимое коллекции меняется, открытие всплывающего окна по-прежнему занимает несколько секунд: (

4b9b3361

Ответ 1

Согласно этому блогу: http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx

Я тестировал его с помощью этого кода:

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

Он отлично работает в первый раз и в следующий раз. Не нужно кодировать эти строки:

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

Надеюсь, это поможет вам.

Ответ 2

У меня была проблема с низкой производительностью. Но я создал класс, унаследовавший форму Combobox, поэтому я хотел бы сделать это программно. Итак, вот это решение для других гуглеров.

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

Ответ 3

Я просто столкнулся с этой проблемой. Я использую этот код в пользовательском поле со списком с шаблоном стиля. Когда я запускал свой код в режиме отладки VS, виртуализация не работала должным образом. Как только я запустил его вне отладки, я могу переключить содержимое ObservableCollection без блокировки UI. Это также может помочь, если вы установите максимальную высоту и максимальную ширину.

<Setter Property="ScrollViewer.CanContentScroll" Value="True"/> 
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
<Popup>
    <Border/>
    <ScrollViewer>
      <VirtualizingStackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
    </ScrollViewer> 
  </Grid>
</Popup>