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>
А для ленивых вот скриншот: