from - Problemas de rendimiento de WPF ComboBox vinculando colecciones grandes
wpf combobox selectionchanged (3)
Estoy tratando de vincular una gran colección a un ComboBox y me enfrenté a problemas de rendimiento al abrir la ventana emergente de ComboBox. Busqué en Internet y descubrí que usar VirtualizingStackPanel como plantilla de panel de elementos podría ayudar, pero me ayudó solo parcialmente. Si conecto una gran colección a un ComboBox, podría abrir una ventana emergente muy rápido, eso está bien, pero si después de eso uniré otra colección a un ComboBox e intentaré abrir el popup nuevamente, se volverá muy lento. Lo mismo está sucediendo si abre una ventana emergente para un ComboBox vacío, luego une una gran colección e intenta abrir la ventana emergente de nuevo; demora unos segundos antes de que se abra la ventana emergente.
Aquí está el XAML:
<ComboBox Name="cbBlah">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
y el código de muestra para el enlace para reproducir el problema:
var list = new List<string>();
for (var i = 0; i < new Random().Next(9000, 10000); i++)
list.Add(i.ToString());
cbBlah.ItemsSource = list;
Traté de hacer que el panel de pila de virtualización se viera así:
<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />
pero no ayuda, parece que VirtualizationMode se ignora, por lo que la ventana emergente se abre muy rápido solo la primera vez y luego, cada vez que se realiza el enlace, es muy lenta.
ACTUALIZACIÓN : Pensé en no vincular una nueva colección cada vez, pero unir una ObservableCollection una vez y luego simplemente cambiar su contenido. Lo mismo, tan pronto como el contenido de la colección cambie, abrir una ventana emergente aún demora varios segundos :(
De acuerdo con este blog: http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx
Lo he probado con este código:
<ComboBox Name="cbBlah" ItemsSource="{Binding}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
Funciona bien por primera vez y las próximas veces. No es necesario codificar estas líneas:
<VirtualizingStackPanel VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" />
Espero que esto te ayude.
Me encontré con este problema también. Estoy usando este código en un cuadro combinado personalizado con una plantilla de estilo. Cuando ejecuté mi código en el modo de depuración VS, la virtualización no funcionó correctamente. Una vez que lo ejecuté fuera de la depuración, puedo cambiar el contenido de ObservableCollection sin bloquear la IU. También podría ser útil si establece una altura máxima y un ancho máximo.
<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>
Tuve el problema con el rendimiento lento también. Pero había creado una clase que heredaba el formulario de Combobox, por lo que me gustaría hacer esto programáticamente. Así que aquí está la solución para otros googlers por ahí.
ItemsPanel = new ItemsPanelTemplate();
var stackPanelTemplate = new FrameworkElementFactory(typeof (VirtualizingStackPanel));
ItemsPanel.VisualTree = stackPanelTemplate;