This article has been localized into Ukrainian by the community.
Ресурси
WPF представляє дуже зручну концепцію: можливість зберігати дані як ресурс, або локально для елемента управління, локально для всього вікна або глобально для всього додатка. Дані можуть бути майже будь-якими, що завгодно, від фактичної інформації до ієрархії елементів керування WPF. Це дозволяє розміщувати дані в одному місці, а потім використовувати їх із кількох інших місць, що дуже корисно.
Концепція широко використовується для стилів та шаблонів, про що ми поговоримо далі у цьому посібнику, але, як це буде проілюстровано в цьому розділі, ви можете використовувати її і для багатьох інших речей. Дозвольте продемонструвати це на простому прикладі:
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourceSample" Height="150" Width="350">
<Window.Resources>
<sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
<TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
</StackPanel>
</Window>
Ресурси отримують ключ за допомогою атрибута x: Key, що дозволяє посилатися на нього з інших частин програми за допомогою цього ключа в поєднанні з розширенням розмітки StaticResource. У цьому прикладі я просто зберігаю простий рядок, який потім використовую з двох різних елементів керування TextBlock.
StaticResource проти DynamicResource
У прикладах до цього часу я використовував розширення розмітки StaticResource для посилання на ресурс. Однак існує альтернатива у вигляді DynamicResource.
Основна відмінність полягає в тому, що статичний ресурс вирішується лише один раз, саме в той момент, коли завантажується XAML. Якщо згодом ресурс буде змінено, ця зміна не буде відображена там, де ви використовували StaticResource.
DynamicResource, з іншого боку, вирішується, коли це насправді потрібно, а потім знову, якщо ресурс змінюється. Подумайте про це як про прив’язку до статичного значення проти прив’язки до функції, яка відстежує це значення і надсилає його вам щоразу, коли воно змінюється - це не зовсім так, як це працює, але воно має дати вам краще уявлення про те, коли що використовувати. Динамічні ресурси також дозволяють використовувати ресурси, яких немає навіть під час проектування, наприклад якщо ви додаєте їх із Code-behind під час запуску програми.
Інші типи ресурсів
Поділитися простим рядком було просто, але ви можете зробити набагато більше. У наступному прикладі я також збережу повний масив рядків, а також градієнтний пензель, який буде використовуватися для фону. Це має дати вам досить гарне уявлення про те, скільки ви можете зробити з ресурсами:
<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ExtendedResourceSample" Height="160" Width="300"
Background="{DynamicResource WindowBackgroundBrush}">
<Window.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
<x:Array x:Key="ComboBoxItems" Type="sys:String">
<sys:String>Item #1</sys:String>
<sys:String>Item #2</sys:String>
<sys:String>Item #3</sys:String>
</x:Array>
<LinearGradientBrush x:Key="WindowBackgroundBrush">
<GradientStop Offset="0" Color="Silver"/>
<GradientStop Offset="1" Color="Gray"/>
</LinearGradientBrush>
</Window.Resources>
<StackPanel Margin="10">
<Label Content="{StaticResource ComboBoxTitle}" />
<ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
</StackPanel>
</Window>
Цього разу ми додали кілька додаткових ресурсів, так що наше Вікно тепер містить простий рядок, масив рядків та LinearGradientBrush. Рядок використовується для мітки, масив рядків використовується як елементи для елемента керування ComboBox, а пензель градієнта використовується як фон для усього вікна. Отже, як бачите, майже все, що можна, може зберігатися як ресурс.
Місцеві та загальнодоступні ресурси
На даний момент ми зберігаємо ресурси на рівні вікна, це означає, що ви можете отримати до них доступ з усього вікна.
Якщо вам потрібен даний ресурс лише для певного елемента керування, ви можете зробити його більш локальним, додавши його до цього конкретного елемента керування, замість вікна. Він працює точно так само, з тією лише різницею, що тепер ви можете отримати доступ лише з тієї області контролю, куди ви його помістили:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
У цьому випадку ми додаємо ресурс до StackPanel, а потім використовуємо його з його дочірнього контролу, Label. Інші елементи керування всередині StackPanel могли б також використовувати його, як і дочірні до цих дочірніх елементів керування могли б отримати до нього доступ. Однак елементи керування поза цим StackPanel не матимуть до нього доступу.
Якщо вам потрібна можливість отримати доступ до ресурсу з кількох вікон, це можливо також. Файл App.xaml може містити такі ресурси, як вікно та будь-який елемент керування WPF, і коли ви зберігаєте їх у App.xaml, вони є загальнодоступними у всіх вікнах та елементах керування користувачами проекту . Це працює точно так само, як при зберіганні та використанні з вікна:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</Application.Resources>
</Application>
Його використання також те саме - WPF автоматично перейде в область дії, від локального елемента керування до вікна, а потім до App.xaml, щоб знайти даний ресурс:
<Label Content="{StaticResource ComboBoxTitle}" />
Ресурси з Code-behind
Наразі ми отримали доступ до всіх своїх ресурсів безпосередньо з XAML, використовуючи розширення розмітки. Тим не менш, ви, звичайно, можете отримати доступ до своїх ресурсів і з-за коду, що може бути корисним у кількох ситуаціях. У попередньому прикладі ми побачили, як ми можемо зберігати ресурси в декількох різних місцях, тому в цьому прикладі ми будемо отримувати доступ до трьох різних ресурсів із Code-behind, кожен з яких зберігається в різній області:
App.xaml:
<Application x:Class="WpfTutorialSamples.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="WPF application/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application world!</sys:String>
</Application.Resources>
</Application>
Вікно:
<Window x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ResourcesFromCodeBehindSample" Height="175" Width="250">
<Window.Resources>
<sys:String x:Key="strWindow">Hello, Window world!</sys:String>
</Window.Resources>
<DockPanel Margin="10" Name="pnlMain">
<DockPanel.Resources>
<sys:String x:Key="strPanel">Hello, Panel world!</sys:String>
</DockPanel.Resources>
<WrapPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10">
<Button Name="btnClickMe" Click="btnClickMe_Click">Click me!</Button>
</WrapPanel>
<ListBox Name="lbResult" />
</DockPanel>
</Window>
Code-behind:
using System;
using System.Windows;
namespace WpfTutorialSamples.WPF_Application
{
public partial class ResourcesFromCodeBehindSample : Window
{
public ResourcesFromCodeBehindSample()
{
InitializeComponent();
}
private void btnClickMe_Click(object sender, RoutedEventArgs e)
{
lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
lbResult.Items.Add(this.FindResource("strWindow").ToString());
lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
}
}
}
Отже, як бачите, ми зберігаємо три різні "Привіт, світ!" повідомлення: одне в App.xaml, одне всередині вікна та одне локально для головної панелі. Інтерфейс складається з кнопки та ListBox.
У Code-behind ми обробляємо подію натискання кнопки, в якій ми додаємо кожен з текстових рядків до ListBox, як показано на знімку екрана. Ми використовуємо метод FindResource(), який повертає ресурс як об’єкт (якщо він знайдений), а потім перетворюємо його у рядок, про який ми знаємо, за допомогою методу ToString().
Зверніть увагу, як ми використовуємо метод FindResource() у різних сферах - спочатку на панелі, потім у вікні, а потім у поточному об’єкті Application. Має сенс шукати ресурс там, де ми знаємо, що він є, але, як уже зазначалося, якщо ресурс не знайдений, пошук прогресує вгору по ієрархії, тому, в принципі, ми могли б використовувати метод FindResource() на панелі в усі три випадки, оскільки це продовжувалося б до вікна, а пізніше - до рівня програми, якщо не було знайдено.
Те саме не вірно і навпаки - пошук не рухається по дереву, тому ви не можете почати пошук ресурсу на рівні програми, якщо він був визначений локально для елемента керування або для вікна.