Проблемы производительности WPF ComboBox при связывании больших коллекций - PullRequest
45 голосов
/ 20 ноября 2011

Я пытаюсь привязать большую коллекцию к ComboBox, и у меня возникли проблемы с производительностью при открытии всплывающего окна ComboBox. Я искал интернет и обнаружил, что использование VirtualizingStackPanel в качестве шаблона панели элементов может помочь, но это помогло только частично. Если я связываю большую коллекцию с 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 игнорируется, поэтому всплывающее окно открывается очень быстро только в первый раз, а затем, каждый раз после изменения привязки, очень медленно.

ОБНОВЛЕНИЕ : Я думал о том, чтобы не связывать новую коллекцию каждый раз, а связывать ObservableCollection один раз, а затем просто изменять ее содержимое. То же самое, как только меняется содержимое коллекции, открытие всплывающего окна все равно занимает несколько секунд: (

Ответы [ 3 ]

100 голосов
/ 12 января 2012

Согласно этому блогу: 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" />

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

9 голосов
/ 20 августа 2015

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

ItemsPanel = new ItemsPanelTemplate();
var stackPanelTemplate = new FrameworkElementFactory(typeof (VirtualizingStackPanel));
ItemsPanel.VisualTree = stackPanelTemplate;
0 голосов
/ 15 июля 2015

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

<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>
...