MergedDictionaries и поиск ресурсов - PullRequest
19 голосов
/ 14 июля 2011

У меня проблема со словарями ресурсов и слияниями в целом, особенно когда речь идет о производительности поиска ресурсов. После некоторого тестирования производительности я обнаружил, что 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 ]

46 голосов
/ 29 июля 2011

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

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

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

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

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

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

С уважением, Нико

4 голосов
/ 05 января 2012

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

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

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

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

1 голос
/ 05 августа 2011

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

0 голосов
/ 12 июля 2012

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

...