2010-09-21 20 views
5

He estado luchando contra un ComboBox "lento" de WPF esta mañana, y me encantaría ver si alguien tiene consejos para eliminar este problema.Diagnóstico de problemas de rendimiento con WPF de datos ComboBox

Digamos que tengo dos ComboBoxes, A y B. Cuando A cambia, los elementos en B también cambian. El ComboBoxes cada uno tiene su enlace de datos y SelectedItem ItemsSource así:

<ComboBox Grid.Column="1" ItemsSource="{Binding Names}" SelectedItem="{Binding CurrentName, Mode=TwoWay}" Margin="3" MinWidth="100" /> 
<ComboBox Grid.Column="1" Grid.Row="1" ItemsSource="{Binding SubNames}" SelectedItem="{Binding CurrentSubName, Mode=TwoWay}" Margin="3" MinWidth="100" /> 

Cada vez que la lista de B tiene que cambiar, lo hago en la limpieza de subnombres y luego volver a agregar las entradas en base a la SelectedItem en A. Esto es hecho porque sobrescribir SubNames con un nuevo ObservableCollection<string> rompe el enlace de datos.

Todo en una computadora funciona como usted espera. Seleccione A, luego haga clic en B y los nuevos elementos aparecerán inmediatamente. En otra computadora, cuando hago esto, hay una pausa de hasta 5 segundos antes de que se muestre el ComboBox. La cantidad de artículos es exactamente la misma. Una diferencia es que en la máquina lenta, hay cosas sucediendo en el fondo con la comunicación de hardware. Congelé todos esos hilos y no ayudó.

Mi mayor problema es que no puedo averiguar por dónde empezar a buscar. Necesito ver qué está haciendo el sistema en el momento en que se hace clic en el ComboBox. Estoy usando databinding, por lo que no puedo poner un punto de interrupción en ningún lado. Traté de cambiar mi declaración de subnombres de

public ObservableCollection<string> SubNames { get; set; } 

a

private ObservableCollection<string> subnames_ = new ObservableCollection<string>(); 
public ObservableCollection<string> SubNames 
{ 
    get { return subnames_; } 
    set { subnames_ = value; } 
} 

y luego poner puntos de interrupción en el getter y setter para ver si había lectura excesiva o la escritura pasando, pero no estaba' t cualquier.

¿Alguien puede sugerirme un próximo paso para intentar determinar el origen de esta ralentización? No creo que tenga nada que ver con la plantilla de stock de ComboBox, como se describe en in this article.

+1

¿Puede verificar que sigue siendo así cuando lo ejecuta fuera de una sesión de depuración? – ArielBH

+1

¡Me olvidé por completo de esta pregunta! Encontré una publicación en algún lugar que sugería que solo ocurre dentro del depurador, y efectivamente, ese era el caso. Pero desde entonces he cambiado el código para usar ICollectionView para todo, y creo que ahora es bastante rápido incluso dentro del depurador. – Dave

+0

Me salvaste horas de depuración. Yo uso CollectionViewSource (y List ) y en la depuración tarda 3-4sec. para abrir un ComboBox después de establecer ItemsSource, pero fuera del depurador funciona mucho más rápido. Gracias por señalar eso. – surfen

Respuesta

2

Si bien esto puede no responder directamente a su pregunta, una sugerencia sería no vincular directamente a la ObservableCollection. Como la colección puede generar muchos eventos al manipular sus contenidos, es mejor vincular ItemsControl a un ICollectionView que represente a ObservableCollection, y al actualizar la colección use ICollectionView.DeferRefresh().

Lo que suelo hacer es crear una clase derivada de ObservableCollection que expone una propiedad DefaultView, que ejemplifica perezosamente el ICollectionView correspondiente a la colección. A continuación, vinculo todos los ItemsControls a la propiedad collection.DefaultView. Entonces, cuando necesito refrescar o manipular los elementos de la colección, que utilizo:

using (collection.DefaultView.DeferRefresh()) { 
    collection. // add/remove/replace/clear etc 
} 

Esto actualiza los controles enlazados sólo después de que el objeto devuelto por DeferRefresh() se ha eliminado.

También tenga en cuenta que los mecanismos de enlace en WPF tienen un TraceSource predeterminado que puede utilizar para obtener más información sobre los enlaces mismos; que no remonta el tiempo, así que no estoy seguro de lo útil que es, pero se puede activar con:

System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Verbose; 

(o cualquier otro nivel que prefiera).

+0

Gracias por la sugerencia. Es gracioso, acabo de toparme con un problema que está directamente relacionado con lo que has dicho: demasiados eventos son despedidos, y con la dependencia entre los dos, me atrapan en bucles circulares extraños donde intento actualizar el El combobox principal está causando que cosas extrañas sucedan con el segundo. Voy a mirar ICollectionView, lo cual, curiosamente, lo he usado antes, pero no recuerdo nada al respecto. :) – Dave

+0

¿Puede recomendar alguna estrategia general para la situación en la que seleccionar un elemento del cuadro combinado A cambia todo el contenido del cuadro combinado B? Normalmente borro() y agrego() a un ObservableCollection, que funciona, pero como usted señaló, es bueno tener más control sobre los eventos que son despedidos. Di un paso intermedio e intenté usar un ICollectionView: utilicé GetDefaultView() como medio para recrear los datos que aparecen en mi cuadro combinado B, pero no funciona de esa manera: el contenido original permanece. ¿Alguna idea de lo que me falta aquí? Probé Refresh() y eso no ayudó. – Dave

+0

Umm ... bien entonces. Lo que normalmente hago es tener una propiedad de tipo ICollectionView en mi ViewModel y crear una instancia de ListCollectionView cuando se accede por primera vez, que envuelve ObservableCollection que también forma parte de ViewModel. Para simplificar todo eso, extendí ObservableCollection para hacerlo automáticamente en una propiedad llamada DefaultView; ahora puedo exponer el ObservableCollection en ViewModel y enlazar a su propiedad DefaultView en XAML si es necesario. De esta forma, ICollectionView se sincronizará automáticamente cuando cambie la colección que está detrás de él. –

Cuestiones relacionadas