Объединенные словари и поиск ресурсов
У меня проблема с ресурсными словарями и сложенными словарями в целом, особенно когда речь идет о производительности ресурса. После некоторого тестирования производительности я обнаружил, что ResourceDictionary.get_MergedDictionaries - это вызов с наибольшим количеством ударов (проверяется в профилировщике ANTS). У нас есть около ~ 300 ресурсных словарей xamls, и многие из них используют объединенный словарь для "включения" других стилей. Ну, get_MergedDictionaries рассчитывают на одну часть нашего приложения, где мало что происходит, было около 10 миллионов обращений. Поэтому я предполагаю, что мы делаем что-то совершенно неправильное с ресурсными словарями в целом. Поэтому я попытался реорганизовать все, и я хочу попытаться избавиться от всех объединенных словарей.
Теперь на вопрос. Я пытался избавиться от сложенных словарей, но я потерпел неудачу. Я понимаю, что при использовании StaticResource для поиска требуется ресурс, который должен быть определен до текущего. Я сделал следующий короткий пример:
Один основной проект и одна пользовательская библиотека управления.
пользовательская библиотека управления содержит 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>
Теперь в основном проекте MainWindow.xaml выглядит так:
<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>
Это желаемая цель. но, к сожалению, это происходит из-за того, что ресурс "myColor" не найден. Я, конечно, знаю, как это исправить, добавьте объединенный словарь в Templates.xaml и ссылку Colors.xaml, но я всегда думал, что я никогда не проверял, что ресурсы просматриваются в зависимости от логического дерева и ресурсов элемента. Мое понимание; Создается кнопка; попробуйте найти шаблон.. found; попробуйте найти цвет, не найти на собственных ресурсах, подойти и использовать ресурсы Windows.
Кажется, я ошибаюсь.
Поэтому я надеюсь, что кто-то может пролить свет на это для меня. Мы активно используем WPF, и, несмотря на это, мы многого добились с ним, но из-за неправильного обучения в начале, наша производительность довольно плохая только из-за поиска ресурсов.
Любая помощь будет принята с благодарностью
Спасибо заранее
С наилучшими пожеланиями
Нико
Ответы
Ответ 1
Ну, мне не нравится отвечать на мой собственный вопрос, но я думаю, что многие люди могут наткнуться на это, и я хочу дать им наше текущее решение в качестве опции для рассмотрения.
Как я уже говорил, у нас много XAML, около ~ 300 для всех разных вещей, таких как Shared Resources (Brushes, Colors), а также много XAML, содержащих разные DataTemplates, стили для элементов управления, а также для пользовательских элементов управления. Вначале этот подход с большим количеством XAML был для нас разумным, потому что мы делаем то же самое с нашими классами и сохраняем их небольшими и организованными.
К сожалению, WPF это не нравится. Чем больше ресурсов у вас есть и чем больше вы объедините их через MergedDictionaries, тем хуже будет ваша производительность.
Лучший совет, который я могу вам дать, использовать как можно меньше ResourceDictionary XAMLs.
Мы запустили пулю и объединили много из них в один гигантский XAML, фактически мы делаем это сейчас с предварительным компилятором, сохраняющим лучшее из обоих миров. Мы можем использовать столько XAML, сколько хотим, просто следуя нескольким ограничениям и объединим их при компиляции в гигантском XAML. Увеличение производительности, которое мы получаем, было замечательным. В моем вопросе я написал "11 миллионов хитов на getMergedDictionaries"... просто "предварительно скомпилировав" одну из наших сборок, мы снизились до 2 миллионов просмотров, а производительность во всем приложении во все времена намного лучше.
Итак, в конце концов. Ресурсы XAML не следует рассматривать как исходный код, который компилируется, вместо этого он должен пониматься как фактический ресурс, который при объявлении существует, занимает пространство и производительность.
Ну, мы должны были узнать, что трудно. Я надеюсь, что все, кто это прочитает, могут улучшить свои проекты, узнав о наших ошибках.
Спасибо за все комментарии и предложения.
С уважением
Нико
Ответ 2
Я склонен идти по пути использования только одного ResourceDictionary в приложении, чтобы избежать каких-либо проблем с производительностью.
Чтобы XAML был управляемым, я использую модуль XAML для Visual Studio и обертываю каждую категорию ресурсов в регионе.
- Щетки
- Стили текста
- и т.д...
Для этого сценария плагин является абсолютным спасателем жизни.
http://visualstudiogallery.msdn.microsoft.com/3c534623-bb05-417f-afc0-c9e26bf0e177
Ответ 3
Использование SharedResourceDictionary вместо ResourceDictionary полностью разрешило проблему производительности MergedDictionaries для меня:
http://www.wpftutorial.net/MergedDictionaryPerformance.html
Ответ 4
Был ли какой-либо свет на процедуру поиска ресурсов? Почему "myColor" не найден?
Кстати, я нашел способ заставить его работать, но странный и неустойчивый способ. Если Application.xaml имеет этот код, цвет должен быть найден:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Colors.xaml"/>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceTestLib;component/Themes/Template.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
Если, с другой стороны, вы включаете этот код в другой XAML, который затем включаете в Application.xaml - он не работает, хотя структуры ресурсов идентичны (проверено с помощью Snoop).