2011-04-26 10 views
23

Tengo una aplicación WPF, y es lenta.WPF: instanciación de plantilla lenta

Es NO la representación. En primer lugar, el renderizado es bastante simple, y en segundo lugar, lo analicé con WPF Performance Toolkit: nada.

Es NOT en mi propio código. En primer lugar, las pruebas de la unidad funcionan rápido, y en segundo lugar, si reemplazo todas las plantillas de datos con las plantillas en blanco, todo funciona rápido.

Hasta ahora, parece que la parte lenta es la instanciación de la plantilla . Es decir, cuando inicia la aplicación y abre una pantalla complicada, toma mucho de tiempo. Y por "mucho" quiero decir "mucho". Algunas veces puede durar hasta 3-5 segundos, por ejemplo, cuando hay una cuadrícula de datos con 100 filas. Pero cuando vas a otra pestaña, y luego regresas a esa misma pantalla, se abre rápido (mientras su modelo de vista permanezca).

Esto es muy molesto no solo porque es lento, sino porque no puedo hacer nada al respecto. Si tuviera algún control sobre la lentitud, podría, tal vez, mostrar un poco de "de apertura, por favor espere" mensaje o algo ...

Además, cuando miro a algunas otras aplicaciones WPF (más notablemente, ILSpy) , parecen funcionar razonablemente rápido, a pesar de la gran cantidad de datos. Esto me hace creer que probablemente estoy haciendo algo mal. Pero no tengo idea de por dónde empezar.

¿Alguna idea? Cualquier error clásico? ¿Algun consejo?

+0

Te estás preguntando y haciendo conjeturas sobre cuál es el problema. No te preguntes No adivine, y no espere que Performance Toolkit se lo diga. [Aquí le mostramos cómo averiguarlo]] (http://stackoverflow.com/questions/375913/what-can-i-use-to-profile-c-code-in-linux/378024#378024) –

+0

@Mike: Sí , Uso esta técnica de muestreo primitiva ampliamente, y me ayuda mucho cuando hay una degradación general del rendimiento. Pero en este caso, simplemente no tengo tiempo suficiente para detener la ejecución, ya que la degradación del rendimiento solo dura, como máximo, 3-5 segundos. Además, en las raras ocasiones en que logré detenerlo, siempre se detiene en las entrañas de WPF. Sí busco esa pista también (con la ayuda de ILSpy), pero hasta ahora parece bastante sin esperanza. Por lo tanto, mi pregunta es más similar a lo que podría estar haciendo mal con WPF. –

+0

Derecha. Se detiene en las agallas de WPF, pero ¿qué hay en la pila? Cada línea en la pila es responsable de ese tiempo. He tenido personas que dicen "Oh, cada vez que lo detengo, está en algún iterador. ¿De qué sirve eso?" La respuesta es * excelente *, ahora solo busca la pila y verás el problema. Si tiene una conjetura sobre cuál es el problema, eso le dirá si tiene razón, y si está equivocado, le dirá cuál es el problema correcto. –

Respuesta

1

¿Está ejecutando su aplicación WPF como una aplicación de 64 bits?

Entonces WPF slow to start on x64 in .NET Framework 4.0 podría ayudar.

+0

Se veía bien, pero no. En primer lugar, en realidad ejecuto la aplicación como un proceso de 32 bits (uso algunos archivos DLL nativos que no existen en 64 bits). En segundo lugar, es tan lento incluso cuando sé con certeza que todo el código relevante ya ha sido JITted. Así es como sé esto: lanzo la aplicación, creo un nuevo proyecto (tengo estos conceptos de 'proyectos'), pruebo la interfaz de usuario y veo que es lenta. Luego, creo un nuevo proyecto OTRA VEZ (¡sin cerrar la aplicación!). En este punto, todos los modelos y viewmodels antiguos se descartan, y se crean otros nuevos. Luego vuelvo a probar la UI, y vuelve a ser lento. –

5

Mi exerience viene de trabajar en la aplicación de mapas mentales WPF NovaMind

Un par de meses atrás que reescribió por completo nuestra capa intermedia para resolver los problemas de rendimiento que habíamos experimentado. En pocas palabras, la creación de nuestros controles de usuario parecía ser mucho más lenta. Lamentablemente, no pude encontrar una forma excelente de perfilar el rendimiento, ya que ni WPF Performance Suite ni las aplicaciones comerciales como ANTS Profiler le brindan información detallada sobre esta parte del proceso de WPF. (Pedí this question en ese entonces)

Recurrimos a probar manualmente nuestra aplicación por prueba y error y eliminamos partes de nuestros controles de usuario para ver exactamente cuál es el culpable.

Al final resolvimos los problemas de rendimiento al reescribir completamente nuestros controles. También reducimos drásticamente la complejidad de nuestro árbol visual. Antes de la reescritura, uno de los controles de usuario más utilizados, cuando se inspeccionaba con Snoop, consistía en 61 elementos diferentes, ahora solo hay 3. Siempre que sea posible, solo agregamos elementos al árbol visual a pedido. (Como ya sabe en XAML, incluso cuando configura las cosas en Colapsar, primero deben crearse). Finalmente, nos vimos obligados a escribir nuestro propio control de representación de texto enriquecido, ya que el RichtextBox incorporado es ridículamente lento y el árbol visual de RichtextBox es bastante complejo.

No sé si esto se aplicará a su situación, pero le recomendaría que investigue sus controles de usuario y vea si son complejos. Quizás tengas cosas que puedas recortar. Las frutas que cuelgan poco serían las partes que solo son raramente visibles o pueden crearse de manera perezosa. Podría crear estas partes a partir del código cuando sea necesario en lugar de tenerlas en XAML. Esto debería ayudarte mucho.

De lo contrario, la virtualización es su amigo, si es posible. En nuestro caso, no pudimos hacer eso por desgracia.

+0

Acabo de verificar el tamaño del árbol visual. Una pantalla que tarda aproximadamente 1 segundo en aparecer contiene un total de 850 imágenes. ¿Es esto excesivo en tu experiencia? ¿Qué tamaño de árbol es aceptable? –

1

Control de usuario en su plantilla de datos, no es una mala idea, pero si anhela rendimiento, debería considerar cambiar a un control más ligero. Por ejemplo, tener un UserControl alojando un TextBox es una muy mala idea, ya que UserControl está compuesto por ContentControl, ContentControl aloja ContentPresenter y ContentPresenter alojará TextBox, por lo que si observa su Árbol Visual, tiene tres capas nuevas de Elementos de UI. La reducción de Visual Tree ciertamente mejorará el rendimiento.

Lo más probable es que sugiera crear controles personalizados que pueden ser un control completamente nuevo con pocas propiedades de dependencia que pueden relacionarse con los datos que desea presentar y puede tener su propia plantilla personalizada en generic.xaml. En segundo lugar, simplemente puede derivar un control de los controles existentes y redefinir su plantilla predeterminada en generic.xaml.

Este enfoque funcionará mejor, ya que reducirá su árbol visual, reduciendo así el trabajo del Administrador de estado visual.

Cambiar el tema o la plantilla será más lento que cambiar el elemento que aloja el contenido. Y permita que el elemento tenga la plantilla predeterminada en su propio diccionario de recursos genérico.

1
  • Trate de mover todos los recursos como medida en que se va a ir, preferentemente en App.xaml
  • Comprobar si se puede utilizar StaticResource en lugar de los dinámicos, estáticos son mucho más rápido
  • Si es posible, intente utilizar depedecy propiedades en sus máquinas virtuales, especialmente si tiene muchas de ellas a la vez o si tienen muchas propiedades. Eso evitará que wpf tenga que reflexionar un montón.
+0

1) Los recursos ya están en app.xaml. 2) Nunca uso DynamicResource. Solo estático.3) No se puede hacer eso: en primer lugar, las propiedades de dependencia requieren afinidad de subprocesos, y en segundo lugar, son en realidad mucho más lentas que las propiedades de POCO. Consulte este artículo para obtener más información: http://www.markusegger.com/blog/development.aspx?messageid=3dfccfc5-1a30-4af1-a924-da22f3ff6057 –

+0

las opiniones difieren en el n. ° 3, ya que las propiedades de dependencia del enlace de datos son más rápidas. http://msdn.microsoft.com/en-us/library/bb613546.aspx en cuanto a la afinidad de subprocesos. sí, esto es cierto, pero los controles a los que se une son de todos modos subprocesos, por lo que todavía tiene que lidiar con eso ... bueno, simplemente lo tira :) – aL3891

+0

otro ejemplo, también vea el enlace de artículos relacionados http: // blog .lexique-du-net.com/index.php? post/2010/02/24/DependencyProperties-or-INotifyPropertyChanged – aL3891

1

Menciona que está utilizando un DataGrid con, por ejemplo, 100 filas. Un posible culpable de sus problemas de rendimiento es que cualquiera que sea la cuadrícula de datos que está utilizando no está virtualizando, por lo que su árbol visual es gigantesco.

Normalmente, el largo tiempo de inicio en las pantallas WPF apunta a un gran árbol visual.

No estoy seguro de si está utilizando una plantilla de datos por fila, o una cuadrícula de terceros que une columnas, o qué, pero digamos que tiene 8 columnas con controles. Dependiendo de su cuadrícula/validación/etc, esto podría ser un árbol visual de 20-60 elementos por fila. Si tiene un cuadro combinado, entonces cada elemento del menú desplegable también se puede crear por fila.

Para solucionar este sólo se necesita mirar los detalles, y la adopción de medidas sobre la marcha:

  1. utilizar un control virtualizar tanto como sea posible. Esto significa usar un panel de virtualización dentro de los controles de lista, y asegurarse de que los controles de terceros también (como muchos controles de stock WPF lo hacen de forma predeterminada)
  2. No use demasiados controles de usuario, controles compuestos, etc. Agregar profundidad agrega tiempo y poner la profundidad extra visual del árbol en un datatemplate u otra área repetida se suma rápidamente.
  3. Si todo lo demás falla, mostrar una pantalla simple y agregar controles a través de código para mejorar el rendimiento percibido
1

Esto suena similar a un problema que estaba teniendo. Publiqué la solución aquí: WPF UI Automation issue. Solo publicando para beneficio de los buscadores, ya que tardó siglos en resolverse.

Cuestiones relacionadas