Pregunta

Tengo una ObservableCollection de ViewModels que están sentados en un DataGrid WPF. El DataGrid tiene tres columnas:

  • columna Posición; esto se hace en tiempo de ejecución mediante un control de usuario que muestra la posición de la fila en mi DataGrid
  • Nombre de columna; esto se hace en tiempo de ejecución mediante un control de usuario que muestra el nombre de la columna (sí, necesito un control de usuario para esta función de cómo el nombre se debe mostrar, pero eso es un aparte)
  • Columna de datos; esto se hace en tiempo de ejecución por otro control de usuario.

Mis columnas se definen como sigue:

        <toolkit:DataGrid.Columns>
            <toolkit:DataGridTemplateColumn Header="" MinWidth="35" MaxWidth="35" SortMemberPath="Position.PositionIndex" CanUserSort="True">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Position}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
            <toolkit:DataGridTemplateColumn Header="Name" MinWidth="150" Width="150" SortMemberPath="Name" CanUserSort="True">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Name}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
            <toolkit:DataGridTemplateColumn Header="Data" Width="Auto" CanUserSort="False">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ContentPresenter Content="{Binding Path=Data}"/>
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
            </toolkit:DataGridTemplateColumn>
        </toolkit:DataGrid.Columns>

Por lo tanto, debido a mis filas y columnas son Nombre UserControls, la DataGrid WPF no puede nativa especie en ellos. Así que para facilitar la clasificación, cuando se hace clic en un encabezado de columna, hago un poco de magia ListCollectionView.CustomSort.

Esto es lo que mis clasificadores personalizados se parecen a la columna Nombre:

// Customized sorter, by name, ascending.
public class AscendingNameSorter : IComparer
{
    public int Compare(object x, object y)
    {
        var lhs = (MyViewModel)x;
        var rhs = (MyViewModel)y;

        return lhs.Name.CompareTo(rhs.Name);
    }
}

// Customized sorter, by name, descending.
public class DescendingNameSorter : IComparer
{
    public int Compare(object x, object y)
    {
        var lhs = (MyViewModel)x;
        var rhs = (MyViewModel)y;

        return rhs.Name.CompareTo(lhs.Name);
    }
}

El problema es que esto es increíblemente lento . No puedo entender por qué. Con 10 elementos de la DataGrid, mi solicitud se paraliza durante 3-4 segundos, mientras que se recurre. Pensé ListCollectionView.CustomSort se supone que es la forma más eficiente para ordenar un ObservableCollection ... dónde voy mal?

¿Fue útil?

Solución

WPF está recreando todas sus UserControls cada vez que cambia de clasificación, así que yo creo que algo en la construcción de esos controles es lento. Pero eso es sólo una conjetura.

Usted debe comenzar por la reducción al problema. Aquí hay algunos pasos que puede tomar:

  1. Para saber qué operación se está llevando a 3-4 segundos. Usted no indicó si el retraso ocurre sólo cuando la asignación del valor a CustomSort, o cada vez que se ha establecido la lista de los cambios después de CustomSort. Esto hace una diferencia.

  2. Trate de añadir una columna de texto normal y la clasificación en ella utilizando el tipo incorporado para ver si es rápido o no. Tal vez usted ha hecho esto ya, pero no dijo en su pregunta.

  3. Para fines de diagnóstico detener temporalmente la configuración CustomSort y establecer ListCollectionView.Filter lugar. Establecer en un filtro que siempre devuelve verdadero. Si, a pesar de la desaceleración, el problema está relacionado con el intento de reorganizar ListCollectionView artículos.

  4. editar temporalmente sus plantillas y reemplazar sus UserControls personalizados con algo trivial (por ejemplo <CheckBox/>) para ver si las cosas se aceleran o no.

  5. Definición de puntos de interrupción en los constructores de sus UserControls para ver si están siendo llamados el número esperado de veces (es decir, 10 constructor llama si hay 10 elementos de la lista). Si ellos están siendo llamados más veces de las esperadas, mira a la pila de traza para ver donde las llamadas adicionales están viniendo.

  6. Agregar código a sus constructores UserControl para escribir el DateTime.Now los constructores fueron llamados a la ventana de salida (o un registro, o lo que sea). Esto le dará una idea de la duración de cada toma.

  7. Añadir varios cientos de artículos a su ObservableCollection, ejecute su aplicación lado a lado con VS.NET, haga clic en el botón de clasificación (o lo que sea), luego pulsa la pausa por el botón en VS.NET y mirar el Seguimiento de la pila. Hit Continuar e inmediatamente hit pausa por el Juego de nuevo, a continuación, busque en el seguimiento de la pila de nuevo. Repetir muchas veces. Esto le dará una buena idea de lo que está sucediendo todo el tiempo extra.

Si, como sospecho, el problema es la creación UserControls lentos y vinculante, se encuentra: El problema ocurre en cada cambio de lista y también ocurre cuando se cambia el filtro, las cosas aceleran cada vez que cambie sus UserControls con <CheckBox/>, su constructor sólo se llama una vez por artículo, el tiempo entre llamadas será bastante grande.

Tenga en cuenta que no estoy diciendo que es el constructor de los UserControls que es lento - que podría ser que el control de usuario crea instancias de muchos sub-objetos cuando está enlazado a datos, o que incluye objetos que son lentos o compleja, un subobjeto carga un archivo, o muchas otras causas posibles. La conclusión es que una instancia del DataTemplate en el objeto y agregarlo al árbol visual está haciendo algo lento. Las trazas de la pila deben darle una idea de dónde buscar.

Si resulta ser otra cosa o si no puede entenderlo, simplemente actualizar su pregunta para dar más información sobre lo que revelan las pruebas anteriores, y vamos a tratar de ayudarle.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top