Иерархия ресурсов
65WPF --- Привязка, команды и стили WPF --- Иерархия ресурсов
Каждый элемент имеет собственную коллекцию ресурсов, и 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.