В инфраструктуре WPF все элементы управления плюс элементы Window, Page (используемые при построении навигационных приложений) и UserControl расширяют класс FrameworkElement, так что почти все виджеты предоставляют доступ к ResourceDictionary. Более того, класс Application, хотя и не расширяет FrameworkElement, но поддерживает свойство с идентичным именем Resources, которое предназначено для той же цели.
Определение ресурсов уровня окна
Чтобы приступить к исследованию роли объектных ресурсов, создайте в Visual Studio новый проект приложения WPF по имени ObjectResourcesApp и замените первоначальный элемент Grid горизонтально выровненным диспетчером компоновки StackPanel, внутри которого определите два элемента управления Button (чего вполне достаточно для пояснения роли объектных ресурсов):
Выберите кнопку OK и установите в свойстве Background специальный тип кисти с применением интегрированного редактора кистей (который обсуждался в главе 26). Кисть помещается внутрь области между дескрипторами и :
Чтобы разрешить использовать эту кисть также и в кнопке Cancel (Отмена), область определения RadialGradientBrush должна быть расширена до словаря ресурсов родительского элемента. Например, если переместить RadialGradientBrush в StackPanel, то обе кнопки смогут применять одну и ту же кисть, т.к. они являются дочерними элементами того же самого диспетчера компоновки. Что еще лучше, кисть можно было бы упаковать в словарь ресурсов самого окна, в результате чего ее могли бы свободно использовать все элементы содержимого окна.
Когда необходимо определить ресурс, для установки свойства Resources владельца применяется синтаксис "свойство-элемент". Кроме того, элементу ресурса назначается значение х:Кеу, которое будет использоваться другими частями окна для ссылки на объектный ресурс. Имейте в виду, что атрибуты х:Key и х:Name — не одно и то же! Атрибут х:Name позволяет получать доступ к объекту как к переменной-члену в файле кода, в то время как атрибут х:Кеу дает возможность ссылаться на элемент в словаре ресурсов.
Среда Visual Studio позволяет переместить ресурс на более высокий уровень с применением соответствующего окна Properties. Чтобы сделать это, сначала понадобится идентифицировать свойство, имеющее сложный объект, который необходимо упаковать в виде ресурса (свойство Background в рассматриваемом примере). Справа от свойства находится небольшой квадрат, щелчок на котором приводит к открытию всплывающего меню. Выберите в нем пункт Convert to New Resource (Преобразовать в новый ресурс), как продемонстрировано на рис. 27.3.
Будет запрошено имя ресурса (myBrush) и предложено указать, куда он должен быть помещен. Оставьте отмеченным переключатель This document (Этот документ), который выбирается по умолчанию (рис. 27.4).
В результате определение кисти переместится внутрь дескриптора Window.
Resources:
Свойство Background элемента управления Button обновляется для работы с новым ресурсом:
FontSize="20" Background="{DynamicResource myBrush}"/>
Мастер создания ресурсов определил новый ресурс как динамический (Dynamic Resource). Динамические ресурсы рассматриваются позже, а пока поменяйте тип ресурса на статический (StaticResource):
FontSize="20" Background="{StaticResource myBrush}"/>
Чтобы оценить преимущества, модифицируйте свойство Background кнопки Cancel (Отмена), указав в нем тот же самый ресурс StaticResource, после чего можно будет видеть повторное использование в действии:
FontSize="20" Background="{StaticResource myBrush}"/>
Расширение разметки {StaticResource}
Расширение разметки {StaticResource} применяет ресурс только один раз (при инициализации) ион остается "подключенным" к первоначальному объекту на протяжении всей времени жизни приложения. Некоторые свойства (вроде градиентных переходов) будут обновляться, но в случае создания нового элемента Brush, например, элемент управления не обновится. Чтобы взглянуть на такое поведение в действии, добавьте свойство Name и обработчик события Click к каждому элементу управления Button:
FontSize="20" Background="{StaticResource myBrush}" Click="Ok_OnClick"/>
FontSize="20" Background="{StaticResource myBrush}" Click="Cancel_OnClick"/>
Затем поместите в обработчик события Ok_OnClick следующий код: