c# wpf performance templates

c# - WPF: creación de instancias de plantilla lenta



performance templates (5)

Tengo una aplicación WPF, y es lenta.

No es la prestación. En primer lugar, el renderizado es bastante simple, y en segundo lugar, lo observé con el Kit de herramientas de rendimiento de WPF, nada.

NO está en mi propio código. En primer lugar, las pruebas unitarias funcionan rápido y, en segundo lugar, si sustituyo todas las Plantillas de datos por otras en blanco, todo funcionará rápido.

Hasta ahora, parece que la parte lenta es la creación de instancias de plantilla . Es decir, cuando inicia la aplicación y abre una pantalla complicada, lleva mucho tiempo. Y por " mucho " quiero decir " mucho ". A veces, pueden ser de 3-5 segundos, por ejemplo, cuando hay una cuadrícula de datos con 100 filas. Pero cuando vas a otra pestaña, y luego vuelves a esa misma pantalla, se abre rápidamente (siempre que su modelo de vista permanezca en su lugar).

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, quizás, mostrar algún mensaje de " apertura, espera " o algo así ...

Además, cuando veo otras aplicaciones WPF (especialmente, ILSpy), parecen funcionar razonablemente rápido, a pesar de las grandes cantidades de datos. Esto me hace creer que probablemente estoy haciendo algo mal. Pero no tengo idea de por dónde empezar.

¿Algunas ideas? ¿Algún error clásico? ¿Algun consejo?


El control de usuario en su plantilla de datos no es una mala idea, pero si desea obtener un rendimiento, debería considerar cambiar a un control más ligero. Por ejemplo, tener un UserControl solo para alojar un TextBox es una muy mala idea, ya que UserControl está compuesto por ContentControl, ContentControl aloja ContentPresenter y ContentPresenter hospedará TextBox, por lo que si observa su Árbol Visual, tiene tres capas nuevas de Elementos de UI. Reducir Visual Tree sin duda mejorará el rendimiento.

Lo más probable es que sugiera crear controles personalizados que puedan ser un control completamente nuevo con pocas propiedades de dependencia que puedan relacionarse con los datos que desea presentar y que tenga 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 Visual Tree, reduciendo así el trabajo de Visual State Manager.

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


Esto suena similar a un problema que estaba teniendo. Publiqué la solución aquí: problema de automatización de la interfaz de usuario de WPF . Solo publicando para el beneficio de los buscadores, ya que tomó años resolverlo.

A continuación del comentario en el enlace, solo respondo, aquí está el quid de esa publicación:

Hice lo siguiente:

  1. Hotfix descargado - - http://archive.msdn.microsoft.com/KB978520 (puede no ser necesario)
  2. Hotfix descargado - - http://archive.msdn.microsoft.com/KB2484841 (definitivamente requerido incluso si tienes Windows 7 / .NET 4)
  3. Se mejoró aún más el código (la validación estaba causando un exceso de objetos). ¿Por qué el Estilo WPF para mostrar los errores de validación en ToolTip funciona para un TextBox pero falla para un ComboBox?

Puede ser que solo se requirió el número 3, pero funcionó. Solo publico aquí para que la gente no pierda los días que perdí en perfiladores de memoria, etc.


Mi experiencia proviene de trabajar en la aplicación de mapas mentales WPF NovaMind

Hace un par de meses reescribimos completamente nuestra capa intermedia para resolver los problemas de rendimiento que habíamos experimentado. En pocas palabras, la creación de nuestros controles de usuario parece ser una forma de reducir la velocidad. Desafortunadamente, no pude encontrar una buena manera 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. (Hice esta pregunta en ese entonces)

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

Al final, resolvimos los problemas de rendimiento al reescribir completamente nuestros controles. También reducimos dramáticamente la complejidad de nuestro árbol visual. Antes de la reescritura, uno de nuestros controles de usuario más utilizados, cuando se inspeccionaba con Snoop, consistía en 61 cosas diferentes, ahora solo hay 3. Siempre que sea posible, solo agregamos cosas al árbol visual a pedido. (Como sabe en XAML, incluso cuando configura Colapsado, primero deben crearse). Finalmente, nos vimos obligados a escribir nuestro propio control de representación de texto enriquecido, ya que el RichtextBox integrado 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. Tal vez tienes cosas que podrías recortar. Las frutas colgantes serían partes que rara vez son visibles o pueden crearse de manera perezosa. Puede crear estas partes desde el código que está detrás cuando sea necesario en lugar de tenerlas en XAML. Esto debería ayudarte mucho.

De lo contrario, la virtualización es tu amiga, si es posible. En nuestro caso no pudimos hacer eso desafortunadamente.


Usted menciona que está utilizando un DataGrid con, por ejemplo, 100 filas. Un posible culpable de sus problemas de rendimiento es que cualquier área de datos que esté utilizando no está haciendo virtualización, por lo que su árbol visual es gigantesco.

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

No estoy seguro de si está utilizando una placa de datos por fila, o una cuadrícula de terceros que vincula 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 puede crearse por fila.

Para solucionarlo, solo toma los detalles y toma medidas a medida que avanzas:

  1. Utilice un control de virtualización tanto como sea posible. Esto significa usar un panel de virtualización en el panel de control dentro de la lista y asegurarse de que los controles de terceros también lo hagan (muchos controles WPF de valores ahora lo hacen de manera predeterminada)
  2. No use excesivamente UserControls, controles compuestos, etc. Agregar profundidad agrega tiempo, y agregar profundidad de árbol visual adicional en una placa de datos u otra área repetida se agrega rápidamente.
  3. Si todo lo demás falla, muestre una pantalla simple y agregue controles a través del código para mejorar el rendimiento percibido

  • Intente mover todos los recursos hacia arriba tanto como sea posible, preferiblemente a app.xaml
  • Compruebe si podría usar StaticResource en lugar de los dinámicos, los estáticos son mucho más rápidos
  • Si es posible, intente usar las propiedades de dependencia 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 hacer un montón de reflexión.