Главная » WPF » Ресурсы WPF

0

Самое  первое  место, где программист  сталкивается с необходимостью  отде лить отображение  от самих данных – это ресурсы. У каждого элемента есть свой ство Resources, представляющее собой обычный словарь2, который позволяет  ис кать значение  по ключу. Эта простая  техника применяется в механизмах  подде ржки тем, стилизации и привязки к данным.

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

public class Window1 : Window {

public Window1() {

Title = «Resources»;

Brush toShare = new SolidColorBrush(Colors.Yellow);

Button b = new Button(); b.Content = «My Button»; b.Background = toShare;

Content = b;

}

}

В разметке эта проблема не так проста. Модель грамматического разбора XAML

требует, чтобы все создаваемые объекты были свойствами чего либо. Захоти мы по

Рис. 6.1. Переопределение ресурсов в иерархии элементов

<Window Text=’Resources’ xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’ xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>

<Window.Resources>

<SolidColorBrush x:Key=’toShare’>Yellow</SolidColorBrush>

</Window.Resources>

<Button Background=’{StaticResource toShare}’ > My Button

</Button>

</Window>

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

В данном  примере  мы переопределяем один и тот же ресурс  на нескольких уровнях  дерева элементов.  Сначала  значение  toShare определяется в корневом элементе Window,  так же, как и раньше. Затем оно замещается  во вложенной  па нели StackPanel, где создается  ресурс с таким же именем. Разные  кнопки  могут ссылаться на ресурс с именем toShare и получать разные значения в зависимости от того, в каком месте дерева находятся  (рис. 6.1):

<Window x:Class=’EssentialWPF.Resources’ Title=’Resources’ Visibility=’Visible’

xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’

xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>

<Window.Resources>

<SolidColorBrush x:Key=’toShare’>Yellow</SolidColorBrush>

</Window.Resources>

<StackPanel Margin=’10’>

<Button Background=’{StaticResource toShare}’> Level 1

</Button>

<StackPanel Margin=’10’>

<StackPanel.Resources>

<LinearGradientBrush x:Key=’toShare’ …>

<GradientStop Offset=’0’ Color=’sc# 1,1,1,1’ />

<GradientStop Offset=’1’ Color=’sc# 1,.6,.6,.6’ />

</LinearGradientBrush>

</StackPanel.Resources>

<Button Background=’{StaticResource toShare}’> Level 2

</Button>

</StackPanel>

<Button Background=’{StaticResource toShare}’> Level 1

</Button>

</StackPanel>

</Window>

Путь поиска ресурса несколько  сложнее, чем просто проход вверх по иеирар хии. Просматривается также объект приложения, системная тема и тема по умол чанию для типов. Порядок  просмотра таков:

1.  Иерархия элементов.

2.  Application.Resources.

3.  Тема типа.

4.  Системная тема.

Темы  подробно  рассматриваются в главе  8, а сейчас  еще раз подчеркнем, что элемент, ссылающийся на ресурс, может получать  данные из разных мест. Для  автора  приложения наиболее  интересным аспектом  этой  функциональ ности, наверное, является возможность определять  ресурсы  на уровне прило жения.

В главе  2 мы рассматривали объект  Application.  У него тоже есть свойство

Resources, позволяющее определить  ресурсы, глобальные  для всего приложения:

<Application x:Class=’EssentialWPF.MyApp’ xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’ xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’

<Application.Resources>

<SolidColorBrush x:Key=’toShare’>Purple</SolidColorBrush>

</Application.Resources>

</Application>

Эта техника позволяет  создавать ресурсы, общие для всех страниц, окон и эле ментов  управления На  любом уровне  приложения можно  переопределить гло бальное значение ресурса; как это делается, мы уже видели. В общем случае реко мендуется определять ресурс на самом нижнем возможном уровне. Если некий ресурс используется только в одной панели, то для этой панели его и надо опре делить. Если же ресурс используется в нескольких  окнах, то определить  его сле дует на уровне приложения. Определяя ресурс, важно помнить, что использовать его можно в разных местах. Поскольку каждый элемент WPF может присутство вать только в одном месте дерева отображения, мы не можем надежно использо вать элемент в качестве ресурса:

<Window x:Class=’EssentialWPF.Resources’ Title=’Resources’

xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’

xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>

<Window.Resources>

<TextBox x:Key=’sharedTextBox’ />

</Window.Resources>

<Button Content=’{StaticResource sharedTextBox}’/>

</Window>

Эта разметка будет работать только, если на элемент sharedTextBox есть толь ко одна ссылка. Попытайся мы воспользоваться этим ресурсом еще раз, приложе ние завершится с ошибкой:

<Window x:Class=’EssentialWPF.Resources’ Title=’Resources’

xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’

xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>

<Window.Resources>

<TextBox x:Key=’sharedTextBox’ />

</Window.Resources>

<StackPanel>

<!— это ошибка! —>

<Button Content=’{StaticResource sharedTextBox}’/>

<Button Content=’{StaticResource sharedTextBox}’/>

</StackPanel>

</Window>

В главе 3 мы узнали о том, что делать, когда ресурс требуется использовать бо лее одного раза, – прибегнуть  к классу  FrameworkElementFactory. Для  элемен тов, принадлежащих шаблонам, мы создаем фабрику,  а не сами элементы.  Боль шинству  визуальных объектов  (кистей,  перьев, сеток и т.д.) фабрика  не нужна, так как многократное использование обеспечивается наследованием классу Freezable3.

Возможно,  вы задаетесь  вопросом: «С чего вдруг он завел  речь о ресурсах  в главе, посвященной привязке к данным?»  Дело в том, что, используя ссылки  на статические  ресурсы, мы по существу выполняем присваивание переменной,  как в приведенном выше фрагменте на C#. Когда эта переменная  используется, ника кой связи с исходной переменной  уже нет. Рассмотрим следующий  код:

Brush someBrush = Brushes.Red; Button button1 = new Button(); button1.Background = someBrush; someBrush = Brushes.Yellow;

// button1.Background здесь будет красным

При работе с ресурсами можно либо выполнить аналогичное статическое свя

зывание в форме присваивания, либо организовать динамическое  связывание:

<Window Title=’Resources’ xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’ xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’>

<Window.Resources>

<SolidColorBrush x:Key=’toShare’>Yellow</SolidColorBrush>

</Window.Resources>

<Button Background=’{DynamicResource toShare}’ > My Button

</Button>

</Window>

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

<!— window1.xaml —>

<Button Background=’{DynamicResource toShare}’ Click=’Clicked’> My Button

</Button>

// window1.xaml.cs

3  Объекты класса Freezable поддерживают обобществление благодаря режиму «заморозки», в ко тором они не могут быть изменены. Режим заморозки дает возможность нескольким объектам пользоваться одним и тем же экземпляром, не думая о том, был ли он изменен кем то другим.

void Clicked(object sender, RoutedEventArgs e) { Brush newBrush = new SolidColorBrush(Colors.Blue); this.Resources[«toShare»] = newBrush;

}

Это очень полезный  механизм.  В сочетании  с иерархической областью види мости ресурсов он позволяет  обновить сразу все окна или страницы приложения. Чтобы  выполнить динамическое  связывание ресурса  программно,  нам понадо бится метод FrameworkElement.SetResourceReference:

button1.SetResourceReference( Button.BackgroundProperty,

«toShare»);

Конечно,  такие динамические ссылки  не обходятся  без накладных  расходов, поскольку система должна отслеживать изменения ресурса. При проектировании модели ресурсов мы стремились  создать такой механизм, который мог бы широ ко использоваться в системе для обнаружения ресурсов, не вызывая  серьезного падения производительности. Поэтому ресурсы оптимизированы для достаточно крупных изменений.

При изменении любого ресурса обновляется все дерево. Поэтому статические и динамические ссылки на ресурсы можно использовать во многих местах, стои мость операции  от количества  ссылок не зависит.  А вот часто изменять  ресурсы для обновления пользовательского интерфейса не стоит. Зато и тревожиться по поводу большого числа ссылок на ресурсы не надо.

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

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии