2011-11-20 17 views
36

Estoy tratando de vincular una gran colección a un ComboBox y tuve 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.WPF Problemas de rendimiento de ComboBox vinculando colecciones grandes

Aquí es el XAML:

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

y el código de ejemplo para la unión a 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 la virtualización de panel de pila para tener este aspecto:

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

pero no ayuda, parece que VirtualizationMode se ignora, por lo que las ventanas emergentes se abren muy rápido solo la primera vez y luego, cada vez que el enlace se modifica, es muy lento.

ACTUALIZACIÓN: Pensé en no vincular la nueva colección cada vez, pero unir un ObservableCollection una vez y luego simplemente cambiar su contenido. Lo mismo, tan pronto como el contenido de los cambios de recolección, abriendo una ventana emergente todavía tarda varios segundos :(

+0

echar un vistazo a estas preguntas que le contesté http://stackoverflow.com/a/8555403/920384 – punker76

Respuesta

79

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 próximos tiempos no es necesario codificar estas líneas:..

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

espero que esto le ayuda

+0

tan poco código y funciona como un encanto! – Tafari

+0

¡Usted, señor, es un genio! Esto hizo una GRAN diferencia de rendimiento para mí, y la solución es elegante y simple. ¡Gracias! :) – dbeachy1

+1

¿Es posible lograr esto con el código C#? Estoy implementando una clase que se deriva de Combobox, y me gustaría configurar esto aquí. – jonas

0

Acabo de toparme 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> 
8

tuve el problema con un 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; 
+0

Rompió ese código en el constructor, funcionó maravillosamente. ¡Aclamaciones! – Kris

+0

hermosa solución :) gracias – HuyNA

+0

Soy consciente de que esta es una publicación anterior, pero para otros colegas de Google, esta fue una solución elegante. Acelera las cosas terriblemente. – Chris