Логические (объектные) ресурсы – это произвольные объекты, ассоциированные с элементом WPF. Классы FrameworkElement и FrameworkContentElement определяют словарь Resources с типом System.Windows.ResourceDictionary. Этот словарь хранит коллекцию логических ресурсов элемента. С коллекцией Resources можно работать как в коде, так и в разметке XAML. В последнем случае объект, помещаемый в ресурс, должен обладать конструктором без параметров. Кроме этого, для определения ключа словаря в разметке требуется использовать атрибут x:Key из пространства имён анализатора XAML:
<!-- определение ресурсов для кнопки в XAML -->
<Button x:Name="btn" Content="OK">
<Button.Resources>
<SolidColorBrush x:Key="background" Color="Yellow" />
<SolidColorBrush x:Key="borderBrush" Color="Red" />
</Button.Resources>
</Button>
// эквивалентное определение ресурсов для кнопки в коде
btn.Resources.Add("background", new SolidColorBrush(Colors.Yellow));
btn.Resources.Add("borderBrush", new SolidColorBrush(Colors.Red));
Чтобы сослаться на ресурс в разметке XAML, необходимо использовать расширения разметки StaticResourceExtension или DynamicResourceExtension. При этом указывается ключ ресурса. Анализатор XAML выполняет поиск ресурса по ключу, просматривая коллекцию ресурсов элемента, затем ресурсы родительского элемента, и так далее. Вот почему ресурсы обычно объявляются на уровне родительского окна или объекта Application.
<Window xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Window.Resources>
<SolidColorBrush x:Key="borderBrush" Color="Red" />
</Window.Resources>
<Button Content="OK" BorderBrush="{StaticResource borderBrush}" />
</Window>
Статическая ссылка на ресурс сохраняет объект ресурса, а динамическая – ключ объекта. Поэтому при динамическом использовании любая модификация ресурса (даже после применения) отразится на целевом объекте. Ниже показан пример статического и динамического применения ресурсов в коде:
// статическое применение ресурса с поиском по дереву элементов
btn.Background = (Brush) btn.FindResource("background");
// статическое применение ресурса из заданной коллекции ресурсов
btn.Background = (Brush) window.Resources["background"];
// динамическое применение ресурса
btn.SetResourceReference(Button.BackgroundProperty, "background");
Определение логических ресурсов в XAML часто выносится в отдельный файл ресурсов:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Image x:Key="logo" Source="logo.jpg" />
</ResourceDictionary>
Для того чтобы объединить ресурсы в файлах с коллекцией Resources некоего элемента, следует использовать свойство MergedDictionaries класса ResourceDictionary:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="file1.xaml" />
<ResourceDictionary Source="file2.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>