Ресурсы WPF Два типа ресурсов WPF: • объектные ресурсы (object resource) – определенный .NET-объект, который можно использовать многократно; • ресурсы сборки ( assembly resource) – двоичные данные, встроенные в скомпилированную сборку. Объектные ресурсы WPF WPF ресурсы (объектные ресурсы) – простой способ повторного использования определенных объектов и их значений. Ресурсы можно создавать и использовать как в разметке, так и в коде. Любой элемент, производный от FrameworkElement или FrameworkContentElement, содержит коллекцию ResourceDictionary, которая доступна через свойство Resources. public ResourceDictionary Resources { get; set; } Класс ResourceDictionary реализует интерфейс IDictionary, его внутренняя реализация использует класс Hashtable. Ресурсы хранятся в коллекции в виде пар ключ-значение. Обычно ключ - это строка, но можно использовать и другие типы. Каждый ресурс в коллекции ResourceDictionary должен иметь уникальный ключ: • при определении ресурса в разметке уникальный ключ определяется через атрибут x:KeyAttribute; • при определении ресурса в коде ключ указывается как параметр метода Add. Можно определить ресурсы в любом элементе. Дочерний элемент имеет доступ к любому ресурсу, определенному в любом из родительских элементов. По этой причине ресурсы обычно определяются в корневом элементе окна, страницы или приложения. Свойство Resources возвращает только словарь ресурсов, объявленный непосредственно внутри данного элемента. Пример определения ресурса в разметке В примере два контекстных меню объявлены как ресурсы в элементе Window - одно с ключом “key_Russian_Menu”, другое с ключом “key_English_Menu”. Ресурс с ключом “key_Russian_Menu” используется как значение для свойства ContextMenu элемента listBox1. <Window x:Class="Wpf_Resources.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="394" Width="527" Loaded="Window_Loaded"> <Window.Resources> <ContextMenu x:Key="key_Russian_Menu"> <MenuItem Header="Добавить" Click="Add_Click"></MenuItem> <MenuItem Header="Добавить список" Click="Defaults_Click"></MenuItem> </ContextMenu> <ContextMenu x:Key="key_English_Menu"> <MenuItem Header="Add" Click="Add_Click"></MenuItem> <MenuItem Header="Add Defaults" Click="Defaults_Click"></MenuItem> </ContextMenu> </Window.Resources> <Grid Height="343"> <ListBox Margin="10,50,10,10" Name="listBox1" ContextMenu="{StaticResource key_Russian_Menu}"> </ListBox> </Grid> </Window> Объект пользовательского типа как ресурс В примере два объекта типа CustomData.Data_1 объявлены как ресурсы в объекте Application - один с ключом “datakey_1”, другой с ключом “datakey_2”. При создании объектов для их инициализации будут вызваны конструкторы без параметров. Пространство имен CustomData объявлено в открывающем тэге элемента Application с префиксом zz. Префикс zz используется в элементах разметки, объявляющих объекты типа Data_1. <Application x:Class="Wpf_Resources.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:zz="clr-namespace:Custom_Data" StartupUri="Window1.xaml"> <Application.Resources> <zz:Data_1 x:Key="datakey_1"> </zz:Data_1> <zz:Data_1 x:Key="datakey_2"> </zz:Data_1> </Application.Resources> </Application> Работа с объектными ресурсами в коде Класс FrameworkElement содержит методы для поиска ресурса public Object FindResource ( Object resourceKey ); public Object TryFindResource( Object resourceKey ); Оба метода возвращают ссылку на ресурс с заданным ключом, если ключ найден. Если ресурс не найден, метод FindResource бросает исключение, а метод TryFindResource возвращает null. В примере в обработчике English_Checked (события Checked радиокнопки) выполняется поиск ресурса с ключом “key_English_Menu”. Если ресурс найден и может быть приведен к типу ContextMenu, он используется как значение свойства ContextMenu для ListBox1. private void English_Checked(object sender, RoutedEventArgs e) { ContextMenu menu = listBox1.TryFindResource("key_English_Menu") as ContextMenu; if (menu != null) listBox1.ContextMenu = menu; } Статические и динамические ресурсы WPF После того, как ресурс определен, на него можно ссылаться как в разметке, так и в коде. Ресурс можно использовать как статический или динамический. В разметке определены расширения StaticResource или DynamicResource. При обработке StaticResource просматриваются доступные словари ресурсов. Это происходит в процессе загрузки, в тот момент, когда свойству необходимо присвоить значение из статических ресурсов. При обработке DynamicResource ключ создает выражение, которое вычисляется только в процессе выполнения приложения, и тогда на его основе формируется значение. Синтаксический анализ ресурсов выполняется асинхронно. Ресурс, определенный в XAML , может быть не доступен даже в обработчике события Loaded для элемента, в котором он определен. Доступ к ресурсам из кода эквивалентен ссылке DynamicResource в XAML. Cтатические ресурсы WPF В поисках необходимого ключа для статического ресурса словари ресурсов просматриваются в следующем порядке: • словарь, определенный в элементе, для которого устанавливается свойство; • словари логического дерева элементов в направлении к родительскому элементу вплоть до корневого элемента; • словарь объекта Application. Словари просматриваются в процессе загрузки, в тот момент, когда свойству необходимо присвоить значение из статических ресурсов. Опережающие ссылки (forward reference) не поддерживаются статическими ресурсами. Внутри самого словаря ресурсов ссылку можно сделать только на ранее определенный ресурс. Использование статических ресурсов WPF Статические ресурсы рекомендуется использовать в следующих случаях: • Значение ресурса не изменяется после того, как на него была сделана ссылка в первый раз. • Дизайн приложения концентрирует большую часть своих ресурсов в словарях уровня страниц или приложения и ссылки на ресурсы не вычисляются на основе поведения времени выполнения, например, при загрузке страниц. • Статический ресурс можно использовать, чтобы присвоить значение свойству, которое не является свойством зависимостей. • Можно создать словарь ресурсов и скомпилировать его в DLL для повторного использования. • Ресурс используется для того, чтобы установить большое число свойств зависимостей. Свойства зависимостей имеют поддержку для эффективного кэширования, и в случае, когда значение свойства зависимости можно вычислить при загрузке, использование статических ресурсов повышает эффективность приложения. Использование динамических ресурсов WPF В следующих случаях используются динамические ресурсы: • Значение зависит от параметров, которые станут известны только в период выполнения, например, есть ссылки на значения SystemColors, SystemFonts или SystemParameters. • Словарь ресурсов изменяется во время работы приложения. • Ресурсы имеет внутренние связи, использующие опережающие ссылки (forward reference), которые не поддерживаются статическими ресурсами. • Используется большой ресурс, который может быть запрошен не сразу после загрузки. В отличие от статических ресурсов, динамические ресурсы не загружаются до тех пор, пока не будут использованы. • Создается стиль (style), в котором устанавливаются значения , зависящие от других установок пользователя. • Ресурс используется элементом, для которого в процессе жизни приложения может быть заменен родительский элемент, что возможно изменяет область поиска ресурса.