Статические и динамические ресурсы

61

Из примера предыдущей статьи, в котором применялся статический ресурс (в роли которого выступала кисть изображения), могло сложиться впечатление, что статический ресурс невосприимчив ни к каким вносимым в него изменениям. Однако на самом деле это не так.

Например, предположим, что на каком-то этапе после применения ресурса и отображения окна выполняется следующий код:

ImageBrush brush = (ImageBrush)this.Resources["TileBrush"];
brush.Viewport = new Rect(0,0,5,5);

В этом коде кисть извлекается из коллекции Window.Resources и подвергается кое-каким манипуляциям. (Формально код изменяет размер каждого фрагмента кисти, сжимая улыбающуюся рожицу и теснее упаковывая узор.) Может показаться, что никакой реакции в пользовательском интерфейсе при выполнении этого кода быть не должно — в конце концов, это же статический ресурс. Однако изменение все-таки распространяется на две кнопки. Фактически кнопки обновляются и получают новое значение для свойства Viewport независимо от того, используют они кисть через статический или динамический ресурс.

Причина в том, что класс Brush унаследован от класса по имени Freezable. Класс Freezable обладает средствами для отслеживания базовых изменений (и может "замораживаться" до доступного только для чтения состояния, если ему не нужно изменяться). Это означает, что при каждом изменении кисти в WPF все использующие эту кисть элементы управления обновляются автоматически. И не важно, получают они эту кисть через ресурс или нет.

На этом этапе наверняка возникает вопрос о том, чем же тогда отличаются статические и динамические ресурсы? А вот чем: в случае статического ресурса объект извлекается из коллекции ресурсов только один раз. В зависимости от типа объекта (и способа, которым он используется) любые вносимые в этот объект изменения могут быть замечены сразу же. В случае динамического ресурса, однако, объект отыскивается в коллекции ресурсов при каждом возникновении в нем необходимости. Это означает, что под тем же самым ключом может размещаться и совершенно новый объект, и динамический ресурс будет подхватывать это изменение.

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

this.Resources["TileBrush"] = new SolidColorBrush(Colors.LightBlue);

Динамический ресурс подхватит это изменение, а статический не будет иметь ни малейшего понятия о том, что его кисть была заменена в коллекции Resources какой-то другой, и, следовательно, продолжит пользоваться исходной кистью ImageBrush.

На рисунке показан этот пример в окне, включающем динамический ресурс (верхняя кнопка) и статический ресурс (нижняя кнопка).

Динамический и статический ресурсы

Обычно накладные расходы, связанные с использованием динамического ресурса, не нужны, и приложение может прекрасно работать со статическим ресурсом. Исключением является ситуация, когда создаются ресурсы, зависящие от настроек Windows (например, системных цветов). В таком случае должны применяться динамические ресурсы, чтобы приложение могло реагировать на любое изменение в текущей цветовой схеме. (Если использовать в таком случае статические ресурсы, приложение будет работать со старой цветовой схемой до тех пор, пока пользователь его не перезапустит.)

Динамические свойства рекомендуется использовать только в перечисленных ниже ситуациях:

Не стоит чрезмерно увлекаться динамическими ресурсами. Главная проблема в том, что изменение ресурса не обязательно приводит к обновлению пользовательского интерфейса. (В приведенном примере с кистью обновление происходит, благодаря способу, которым конструируются объекты кисти — в частности потому, что они имеют встроенную поддержку уведомлений.) Однако встречается масса случаев, когда динамическое содержимое должно отображаться в элементе управления так, чтобы этот элемент управления мог самостоятельно подстраиваться под изменение содержимого. В таких ситуациях лучше пользоваться привязкой данных.

В редких случаях динамические ресурсы также используются для ускорения первоначальной загрузки окна. Объясняется это тем, что статические ресурсы всегда загружаются при создании окна, в то время как динамические ресурсы загружаются при их первом использовании. Однако заметными улучшения становятся только в случае, если ресурс является слишком большим и сложным (при этом синтаксический анализ его кода разметки занимает ощутимое время).

Лучший чат для C# программистов