wpf - MergedDictionaries y búsqueda de recursos
performance resourcedictionary (4)
Tengo un problema con los diccionarios de recursos y los diccionarios combinados en general, especialmente cuando se trata del rendimiento de la búsqueda de recursos. Después de algunas pruebas de rendimiento, encontré que ResourceDictionary.get_MergedDictionaries es la llamada con más hits (verificada en el perfilador ANTS). Tenemos alrededor de 300 xamls de diccionario de recursos, y muchos de ellos utilizan el diccionario combinado para "incluir" otros estilos. Bueno, los get_MergedDictionaries cuentan con una parte de nuestra aplicación, donde no está ocurriendo mucho, fueron alrededor de 10 millones de visitas. Así que supongo que estamos haciendo algo completamente mal con los diccionarios de recursos en general. Así que traté de refactorizar todo y quiero deshacerme de todos los diccionarios combinados.
Ahora a la pregunta real. Intenté deshacerme de los mergeddictionaries pero fallé. Mi entendimiento es que cuando usa StaticResource la búsqueda necesita que el recurso se defina antes que el actual. Hice el siguiente breve ejemplo:
Un proyecto principal y una biblioteca de control personalizada.
La biblioteca de control personalizada contiene 2 xamls.
<!-- Colors.xaml -->
<ResourceDictionary [stripped namespaces] >
<SolidColorBrush x:Key="myColor" Color="Green"/>
</ResourceDictionary>
<!-- Templates.xaml -->
<ResourceDictionary [stripped namespaces]>
<ControlTemplate x:Key="myTemplate" TargetType="Button">
<Rectangle Fill="{StaticResource myColor}"/>
</ControlTemplate>
</ResourceDictionary>
Ahora en el proyecto principal, el MainWindow.xaml se ve así
<Window x:Class="ResourceTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Colors.xaml"/>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Template.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Template="{StaticResource myTemplate}"/>
</Grid>
</Window>
Ese es el objetivo deseado. pero desafortunadamente esto falla porque no se puede encontrar el recurso "myColor". Por supuesto, sé cómo solucionarlo, agrego un diccionario combinado en Templates.xaml y referencia Colors.xaml pero siempre pensé, bueno, nunca lo comprobé, que los recursos se buscan según el árbol lógico y los recursos del elemento. Mi entendimiento es; Se crea el botón; tratar de buscar plantilla ... encontrado; intente buscar colores que no se encuentran en sus propios recursos, camine y use los recursos de Windows.
Parece que estoy equivocado. Así que espero que alguien pueda arrojar algo de luz sobre esto por mí. Hacemos un uso intensivo de WPF y, a pesar de esto, logramos mucho con él, pero debido a un comportamiento erróneo aprendido al principio, nuestro rendimiento es bastante malo solo por la búsqueda de recursos. Cualquier ayuda sería apreciada grandemente
Gracias de antemano Saludos Nico
¿Se arrojó alguna luz sobre el procedimiento de búsqueda de recursos? ¿Por qué no se encontró "myColor"?
Por cierto, encontré una manera de hacerlo funcionar, pero una forma extraña e inestable. Si Application.xaml tiene este código, se debe encontrar el color:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Colors.xaml"/>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Template.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
Si, por otro lado, incluye este código en otro XAML, que luego incluye en Application.xaml, no funciona, aunque las estructuras de recursos sean idénticas (verificadas con Snoop).
Bueno, no me gusta responder a mi propia pregunta, pero creo que muchas personas podrían tropezar con esto y quiero darles nuestra solución actual como una opción a considerar.
Como dije antes, tenemos muchos XAML, alrededor de 300 para todo tipo de cosas como recursos compartidos (pinceles, colores) pero también muchos XAML que contienen diferentes plantillas de datos, estilos para controles y controles personalizados. Al principio, este enfoque de tener muchos XAML era razonable para nosotros, porque hacemos lo mismo con nuestras clases y las mantenemos pequeñas y organizadas. Desafortunadamente, a WPF no le gusta eso. Cuantos más ResourceDictionaries tengas y más los fusiones con MergedDictionaries, peor será el rendimiento. El mejor consejo que puedo darte es, usa la menor cantidad posible de XAML ResourceDictionary .
Mordimos la bala y fusionamos muchas de ellas en un XAML gigante, de hecho, lo hacemos ahora con un precompilador que conserva lo mejor de ambos mundos. Podemos usar tantos XAML como queramos, solo siguiendo unas pocas restricciones, y fusionándolos en una compilación en un XAML gigante. El aumento de rendimiento que obtuvimos fue notable. En mi pregunta escribí "11 millones de visitas en getMergedDictionaries" ... simplemente "precompilando" uno de nuestros ensamblajes, bajamos a 2 millones de visitas y el rendimiento es en toda la aplicación en todo momento mucho mejor.
Así que al final. Los recursos XAML no deben considerarse como el código fuente que se compila, sino que debe entenderse como un recurso real que, cuando se declara, existe, ocupa espacio y rendimiento.
Bueno, tuvimos que aprender eso de la manera más difícil. Espero que todos los que lean esto puedan mejorar sus proyectos aprendiendo de nuestros errores.
Gracias por todos los comentarios y sugerencias.
Saludos cordiales Nico
El uso de SharedResourceDictionary en lugar de ResourceDictionary solucionó por completo el problema de rendimiento de MergedDictionaries: http://www.wpftutorial.net/MergedDictionaryPerformance.html
Tiendo a seguir la ruta de usar solo un ResourceDictionary en una aplicación para evitar problemas de rendimiento.
Para mantener el XAML manejable, uso el complemento Visual Studio de las regiones de XAML y envuelvo cada categoría de recursos en una región.
- Cepillos
- Estilos de texto
- etc ...
Para este escenario, el complemento es un salvavidas absoluto. http://visualstudiogallery.msdn.microsoft.com/3c534623-bb05-417f-afc0-c9e26bf0e177