Иерархия ресурсов

65

Каждый элемент имеет собственную коллекцию ресурсов, и WPF производит рекурсивный поиск необходимого ресурса в дереве элементов. Благодаря этому, в примере кисть изображения можно было бы перенести из коллекции Resources окна в коллекцию Resources содержащего все три кнопки элемента StackPanel без изменения способа работы приложения. Ее также можно было бы переместить в коллекцию Button.Resources, но тогда потребовалось бы определять ее для каждой кнопки.

Существует еще одна особенность, которую следует учесть. Статический ресурс всегда должен быть определен в коде разметки перед ссылкой на него. Это означает, что хотя размещение раздела Windows.Resources после основного содержимого формы (панели StackPanel, содержащей все кнопки) вполне допустимо, такое изменение приведет к нарушению работоспособности текущего примера. Столкнувшись с неизвестной статической ссылкой на ресурс, анализатор XAML генерирует исключение. (Эту проблему можно обойти за счет использования динамического ресурса, но веские причины для внесения дополнительных накладных расходов отсутствуют.)

В результате, если необходимо поместить ресурс в элемент кнопки, код разметки должен быть немного перестроен, чтобы ресурс определялся до установки фона. Ниже показан один из возможных способов:

<Button Margin="5" Padding="5" FontWeight="Bold" FontSize="14">
   <Button.Resources>
      <ImageBrush x:Key="TileBrush" TileMode="Tile"
         ViewportUnits="Absolute" Viewport="0 0 10 10"
         ImageSource="happyface.jpg" Opacity="0.3"></ImageBrush>
   </Button.Resources>
   <Button.Background>
      <StaticResource ResourceKey="TileBrush"/>
   </Button.Background>
   <Button.Content>Another Tiled Button</Button.Content>
</Button>

Синтаксис для расширения разметки статического ресурса в этом примере выглядит немного по-другому, поскольку устанавливается во вложенном элементе (а не в атрибуте). Ключ ресурса задается с использованием свойства ResourceKey для указания на правильный ресурс.

<Window x:Class="Resources.TwoResources"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="Resources" Height="300" Width="300" >
   
   <Window.Resources>
      <ImageBrush x:Key="TileBrush" TileMode="Tile"
      ViewportUnits="Absolute" Viewport="0 0 32 32"
      ImageSource="happyface.jpg" Opacity="0.3"></ImageBrush>
   </Window.Resources>
   
   <StackPanel Margin="5">
      <Button Background="{StaticResource TileBrush}" Padding="5"
         FontWeight="Bold" FontSize="14" Margin="5" >A Tiled Button</Button>
      <Button Padding="5" Margin="5"
         FontWeight="Bold" FontSize="14">A Normal Button</Button>
         <Button Background="{DynamicResource TileBrush}" Padding="5" Margin="5"
            FontWeight="Bold" FontSize="14">
      <Button.Resources>
         <ImageBrush x:Key="TileBrush" TileMode="Tile"
            ViewportUnits="Absolute" Viewport="0 0 32 32"
            ImageSource="sadface.jpg" Opacity="0.3"></ImageBrush>
      </Button.Resources>
      <Button.Content>Another Tiled Button</Button.Content>
   </Button>
</StackPanel>
</Window>

Интересно то, что имена ресурсов можно использовать повторно, главное — не применять одно и то же имя более одного раза в рамках одной и той же коллекции.

В данном случае кнопка использует тот ресурс, который находит первым. Поскольку поиск начинается с собственной коллекции Resources, вторая кнопка использует изображение sadface.jpg, в то время как первая кнопка извлекает кисть из содержащего окна и работает с изображением happyface.jpg.

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