WPF StaticResource работает, DynamicResource не работает

В течение дня я безрезультатно пытался создать кучу кистей в теме, а затем использовать их с DynamicResource в пользовательском элементе управления. Что я сделал, это:

  • создать тему generic.xaml, которая содержит стили (работы)
  • добавить словарь для слияния в generic.xaml, содержащий кисти, используемые в приложении (работает)
  • сделать кисти иметь ключи ComponentResourceKey (работает)
  • сделать контроль использовать кисти в качестве статического ресурса (работает)
  • заставить управление использовать кисти как динамический ресурс (НЕ РАБОТАЕТ, источник трассировки ресурса говорит так же: System.Windows.ResourceDictionary Предупреждение: 9: ресурс не найден;)
  • динамически добавить в App.Resources кисть с тем же ключом (работает с динамическим ресурсом, меняет цвета, не работает со статическим ресурсом, как и ожидалось)

Так что моя проблема в том, что я не могу найти способ определить значения по умолчанию в теме, чтобы я мог программно изменить их в приложении. Как StaticResource может найти кисть, а DynamicResource нет?!

Я должен добавить, что я создал статический класс, содержащий ключи ресурсов компонента в качестве свойств, которые я затем использую в xaml как {x:Static UI:ResourceScheme.ControlBackgroundKey}, например. Моя проблема похожа на эту: ComponentResourceKey как проблема DynamicResource только в том, что, если я заменяю статические ключи свойств на разметку XAML для ключа ресурса компонента, он все равно не работает.

Может кто-нибудь помочь мне здесь?:(

3 ответа

Вот разница,

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

Таким образом, статический ресурс в случае пользовательского элемента управления должен быть определен только над определением элемента управления в том же файле generic.xaml. Поэтому, если вы поместите свои кисти в другой xaml, это, конечно, не будет работать в случае статического ресурса.

По этой причине, если другие ресурсы типа xaml не включены в виде какого-либо импорта во время компиляции в том же файле, вы не можете использовать статический ресурс в файле. Это просто означает, что фактический xaml файла / компонента / элемента управления должен содержать фактическую ссылку на статический ресурс, который вы используете.

Теперь у меня есть сомнения относительно того, почему DynamicResource не будет работать, потому что, вероятно, DynamicResource будет искать только ResourceDictionary в приложении (где используется элемент управления), но не generic.xaml.

Я не уверен на 100%, но я чувствую, что если вы определяете пользовательский элемент управления и если вы используете DynamicResource, тогда ваши ресурсы должны находиться в словаре ресурсов приложения или в родительском контейнере словаря ресурсов вашего элемента управления, но это не может быть в файле generic.xaml.,

Поскольку DynamicResource будет искать только ключи в логическом дереве среды выполнения элемента управления, и поэтому он может не найти ресурсы, которые находятся в generic.xaml, если файл generic.xaml явно не добавлен в Application.Resources.

Описание: StaticResource должен быть доступен лексически раньше в том же файле во время компиляции, ресурсы будут доступны в словаре Application.Resources, он все еще может быть найден в логическом дереве, но во время компиляции только в том же dll или в том же файле generic.xaml.

Динамический ресурс должен быть найден в Application.Resources и в логическом дереве элемента управления во время выполнения.

Для получения дополнительной информации, пожалуйста, проверьте ресурсы Обзор

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

  • есть класс ресурсов, который содержит ComponentResourceKeys как статические свойства. Тип, используемый в конструкторе ключей ресурса, является типом этого класса. Это в сборке ресурсов.
  • есть тема для пользовательских элементов управления в другой сборке, сборка Controls, которая определяет некоторые кисти, используя в качестве ключа свойства класса ресурса: {x: Статическое пространство имен:ResourceClass.ResourceKeyProperty}
  • в той же теме шаблоны для элементов управления используют кисти в качестве динамических ресурсов: {DynamicResource {x: Статическое пространство имен:ResourceClass.ResourceKeyProperty}}
  • есть также приложение, которое использует эти элементы управления и которое динамически добавляет пользовательские кисти в ресурсы приложения. Эти кисти имеют те же клавиши, что и в теме.

Конечный результат для этого:

  • элементы управления изначально не используют кисти
  • элементы управления используют кисти, добавленные в ресурсы приложения
  • элементы управления изначально используют кисти, если в теме используется StaticResource, но затем ресурсы приложения игнорируются

Решение для этого, кажется, заключается в перемещении класса ресурсов в библиотеке элементов управления.

Поскольку я до сих пор не знаю, почему это происходит, этот вопрос остается открытым, даже если он немного изменился: почему он не работает в первом сценарии?

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

Поэтому вместо описания решения я опишу нерабочую настройку репро.

Решение

Целевые рамки: 4.6

проектов

  • управления
    • Рекомендации
      • Ресурсы
    • файлы
      • Theme.xaml
  • Ресурсы
    • файлы
      • Keys.cs
  • WpfApplication
    • Рекомендации
      • управления
      • Ресурсы
    • файлы
      • MainWindow.xaml

Содержимое файла

Theme.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:r="clr-namespace:Resources;assembly=Resources">
    <Color x:Key="{x:Static r:Keys.PrettyColor}">Red</Color>
    <SolidColorBrush x:Key="{x:Static r:Keys.PrettyBrush}" 
                     Color="{DynamicResource {x:Static r:Keys.PrettyColor}}" />
</ResourceDictionary>

Keys.cs

namespace Resources {
    using System.Windows;

    public static class Keys {
        public static readonly ComponentResourceKey PrettyBrush =
            new ComponentResourceKey(typeof(Keys), Ids.PrettyBrush);

        public static readonly ComponentResourceKey PrettyColor =
            new ComponentResourceKey(typeof(Keys), Ids.PrettyColor);
    }

    public static class Ids {
        public const string PrettyBrush = "PrettyBrush";
        public const string PrettyColor = "PrettyColor";
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:resources="clr-namespace:Resources;assembly=Resources"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Controls;component/Theme.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <Color x:Key="{x:Static resources:Keys.PrettyColor}">Blue</Color>
        </ResourceDictionary>
    </Window.Resources>
    <Border Background="{DynamicResource {x:Static resources:Keys.PrettyBrush}}" />
</Window>

А для ленивых вот скриншот:

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