MergedDictionaries и поиск ресурсов

У меня есть проблема со словарями ресурсов и объединенными словарями в целом, особенно когда речь идет о производительности поиска ресурсов. После некоторого тестирования производительности я обнаружил, что 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, но я всегда думал, что я никогда не проверял, что ресурсы ищутся в зависимости от логического дерева и ресурсов элемента. Мое понимание Кнопка создана; попробуйте поискать шаблон.. найдено; попробуйте поискать цвета, не найденные на собственных ресурсах, подойти и использовать ресурсы windows.

Кажется, я не прав. Поэтому я надеюсь, что кто-то может пролить свет на это для меня. Мы интенсивно используем WPF, и, несмотря на это, мы многого достигли с ним, но из-за некоторого неправильного поведения в начале наша производительность довольно плоха только из-за поиска ресурсов. Любая помощь будет принята с благодарностью

Заранее спасибо С наилучшими пожеланиями Нико

4 ответа

Решение

Ну, я не люблю отвечать на свой вопрос, но я думаю, что многие люди могут наткнуться на это, и я хочу дать им наше текущее решение в качестве варианта для рассмотрения.

Как я уже говорил, у нас есть много XAML, около ~300 для всех видов вещей, таких как общие ресурсы (кисти, цвета), но также много XAML, содержащих различные шаблоны данных, стили для элементов управления, а также для пользовательских элементов управления. Вначале такой подход с большим количеством XAML был для нас разумным, потому что мы делаем то же самое с нашими классами и делаем их небольшими и организованными. К сожалению, WPF это не нравится. Чем больше у вас ResourceDictionaries и чем больше вы объединяете их с помощью MergedDictionaries, тем хуже будет ваша производительность. Лучший совет, который я могу вам дать, - используйте как можно меньше XAML-файлов ResourceDictionary.

Мы укусили пулю и объединили многие из них в один гигантский XAML, фактически мы делаем это сейчас с помощью прекомпилятора, сохраняющего лучшее из обоих миров. Мы можем использовать столько XAML, сколько захотим, просто следуя нескольким ограничениям и объединяя их в компиляцию в гигантском XAML. Увеличение производительности мы получили замечательно. В своем вопросе я написал "11 миллионов обращений к getMergedDictionaries" ... просто "предварительно скомпилировав" одну из наших сборок, мы сократили до 2 миллионов обращений, и производительность во всем приложении во все времена намного лучше.

Итак, в конце концов. Ресурсы XAML не следует рассматривать как исходный код, который компилируется, вместо этого его следует понимать как реальный ресурс, который, когда он объявлен, существует, занимает пространство и производительность.

Ну, мы должны были изучить этот трудный путь. Я надеюсь, что все, кто читает это, могут улучшить свои проекты, учась на наших ошибках.

Спасибо за все комментарии и предложения.

С наилучшими пожеланиями Нико

Я склонен идти по пути использования только одного ResourceDictionary в приложении, чтобы избежать каких-либо проблем с производительностью.

Чтобы обеспечить управляемость XAML, я использую плагин Visual Studio для регионов XAML и обертываю каждую категорию ресурсов в регионе.

  • Кисти
  • Стили текста
  • так далее...

Для этого сценария плагин является абсолютным спасателем жизни. http://visualstudiogallery.msdn.microsoft.com/3c534623-bb05-417f-afc0-c9e26bf0e177

Использование SharedResourceDictionary вместо ResourceDictionary полностью решило для меня проблему производительности MergedDictionaries: http://www.wpftutorial.net/MergedDictionaryPerformance.html

Был ли пролен свет на процедуру поиска ресурсов? Почему "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).

Другие вопросы по тегам