Использование ресурсов в WPF

Автор: Радж Кумар

В этой статье описано использование ресурсов в WPF.

Есть два типа ресурсов.

  1. Статические ресурсы
  2. Динамические ресурсы

Статические ресурсы — они разрешаются и заносятся в свойство в ходе загрузки XAML, которая проводится перед фактическим запуском приложения. Занесение производится только раз, и все изменения словаря ресурсов игнорируются.

Ссылки на статические ресурсы лучше всего работают в следующих условиях:

  • Большинство ресурсов приложения сосредоточено в словарях ресурсов на уровне страницы или приложения. Ссылки на статические ресурсы не вычисляются повторно после действий во время выполнения, например повторной загрузки страницы, поэтому это дает определенное преимущество в производительности за счет отсутствия необходимости перезагрузки большого числа ссылок на динамические ресурсы, если они не требуются приложению.
  • Задается значение свойства, не относящегося к объекту зависимости или замораживаемому объекту.
  • Создается словарь ресурсов, который будет скомпилирован в DLL и упакован в составе приложения или использован в нескольких приложениях.
  • Создается тема для пользовательского элемента управления и определяются ресурсы, используемые в теме. В этом случае обычно не требуется динамическое поведение; статическое поведение позволяет гарантировать предсказуемость поиска и автономность темы. Ссылка на динамический ресурс, даже если она используется в теме, не будет вычислена до времени выполнения, и есть вероятность, что при применении темы локальный элемент переопределит ключ, на который ссылается тема, и этот локальный элемент появится в пути поиска раньше самой темы. В этом случае поведение темы будет непредсказуемо.
  • Ресурсы используются для задания большого числа свойств зависимостей. Свойства зависимостей отличаются эффективным кэшированием значений, обеспечиваемым системой свойств, поэтому при указании значения свойства зависимости, которое можно вычислить во время загрузке, само свойство зависимости не будет вынуждено проверять выражение заново и может вернуть последнее действующее значение. Это позволяет повысить производительность.
  • Требуется изменить базовый ресурс для всех его потребителей или поддерживать несколько допускающих запись экземпляров для нескольких потребителей с помощью атрибута x: Shared.

Пример:

<Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
        <Style TargetType="Border" x:Key="PageBackground">
            <Setter Property="Background" Value="black"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="TitleText">
            <Setter Property="Background" Value="Green"/>
            <Setter Property="DockPanel.Dock" Value="Top"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="Foreground" Value="#4E87D4"/>
            <Setter Property="FontFamily" Value="Tahoma"/>
            <Setter Property="Margin" Value="0,40,10,10"/>
            <Setter Property="Width" Value="300"></Setter>
        </Style>
        <Style TargetType="TextBlock" x:Key="Label">
            <Setter Property="DockPanel.Dock" Value="Right"/>
            <Setter Property="FontSize" Value="8"/>
            <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Margin" Value="0,3,10,0"/>
            <Setter Property="Width" Value="100"></Setter>
            <Setter Property="Height" Value="20"></Setter>
        </Style>
</Window.Resources>

Вот так ресурсы используются в элементах управления.

<Grid>
        <StackPanel>
            <Border Style="{StaticResource PageBackground}">
                <DockPanel>
                    <TextBlock Style="{StaticResource TitleText}">Страница со статическими ресурсами</TextBlock>
                    <TextBlock Style="{StaticResource Label}">Текст метки</TextBlock>
                    <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="20" Foreground="{StaticResource MyBrush}" Text="Всем привет!" Margin="20" />
                    <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Нажмите, чтобы войти :)</Button>
                    <Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" />
                </DockPanel>
            </Border>
        </StackPanel>
</Grid>

Запустите приложение, и результат будет примерно таким:

Рис. 1.

Динамические ресурсы — динамический ресурс заносит объект Expression в свойство во время загрузки, но не выполняет поиск ресурса до обращения к значению объекта Expression во время выполнения. Это значит, что поиск ресурса откладывается до того момента, когда он потребуется. Пример — упреждающая ссылка на ресурс, определяемый позже в XAML. Другой пример — ресурс, которого до времени выполнения даже не будет существовать. При изменении исходного словаря ресурсов целевой объект будет изменен соответствующим образом.

Ссылки на динамические ресурсы лучше всего работают в следующих условиях:

  • Значение ресурса зависит от факторов, не известных до времени выполнения. Сюда могут относиться системные ресурсы или ресурсы, задаваемые пользователем. Например, можно создать изменяемые значения, ссылающиеся на свойства системы, например цвета, шрифты или другие параметры. Это по-настоящему динамические значения, так как они в итоге берутся из среды выполнения, формируемой пользователем и ОС. Также они могут использоваться в допускающих изменение темах уровня приложения, где ресурсы на уровне страниц должны отражать все изменения.
  • Создаются или используются стили тем для пользовательского элемента управления.
  • Планируется изменение содержимого словаря ресурсов в ходе работы приложения.
  • Имеется сложная структура ресурсов с взаимозависимостями, где может потребоваться упреждающая ссылка. Ссылки на статические ресурсы не поддерживают упреждающие ссылки, но в динамике они поддерживаются, так как ресурс при этом не вычисляется до времени выполнения, и "упреждаемость" ссылки при этом не становится проблемой.
  • Используется ссылка на особенно крупный с точки зрения компиляции или выполнения ресурс, который может не потребоваться сразу после загрузки страницы. Статические ресурсы всегда грузятся из XAML при загрузке страницы; при этом динамический ресурс не будет загружен, пока к нему не обратятся.
  • Создается стиль, где изменяемые значения могут определяться другими значениями, берущимися из темы или других пользовательских параметров.
  • Ресурсы применяются к элементам, которые могут представляться в логическом дереве во время выполнения приложения. Изменение родительского объекта может привести к изменению области поиска ресурса, поэтому для повторного вычисления ресурса в новой области следует использовать динамическую ссылку.

Пример:

<Window.Resources>
        <SolidColorBrush x:Key="brush" Color="Green"  />
        <Style TargetType="Border" x:Key="PageBackground">
            <Setter Property="Background" Value="Gold"/>
        </Style>
</Window.Resources>
 
<Grid>
        <Border Style="{DynamicResource PageBackground}">
        <Button x:Name="btn" Content="Проверка" Click="Button_Click" Background="{DynamicResource brush}" Height="30" Margin="53,130,85,130" />
            </Border>
</Grid>

Применить в коде это можно так.

private void Button_Click(object sender, RoutedEventArgs e)

{

   this.btn.SetResourceReference(BackgroundProperty, "brush");

}

Результат будет такой.