TOC

This article is currently in the process of being translated into Bulgarian (~97% done).

WPF приложение :

Ресурси

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. В този пример просто съхраняваме прост низ (string), който след това се използва от два различна TextBlock контрол-а.

StaticResource и DynamicResource

В примерите досега използвахме разширението StaticResource за рефериране към ресурс. Съществува и алтернатива под формата на DynamicResource.

Основната разлика е, че статичен ресурс определя стойността си само веднъж - в момента на зареждане на XAML. Ако ресурсът се промени по-късно, тази промяна няма да бъде отразена там, където сте използвали StaticResource.

DynamicResource, от друга страна, се определя когато е необходимо, и след това отново, ако ресурсът се промени. Може да се разглежда и като обвързване към статична стойност (за StaticResource) и обвързване към функция (за DynamicResource), която следи тази стойност и ви я изпраща всеки път, когато се променя. Динамичните ресурси също ви позволяват да използвате ресурси, които дори не са определени със създаването на прорамата, напр. ако се добавят през Code-behind след стартиране на приложението.

Други типове ресурси

Споделянето на прост низ (string) беше лесно, но може да се направите много повече. В следващия пример ще съхраним допълнително един масив от низове и една градиентна четка (brush), която ще използваме за фона. Това трябва да ви даде доста добра представа какво може да се прави с ресурсите:

<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>

Този път добавихме няколко допълнителни ресурса, така че нашият прозорец вече съдържа обикновен низ (sys:String), масив от низове (x:Array Type="sys:String") и LinearGradientBrush. Низът се използва за етикета, масивът от низове се използва като елементи за контролата ComboBox, а LinearGradientBrush се използва като фон за целия прозорец. Така че, както можете да видите, почти всичко може да се съхранява като ресурс.

Локални ресурси и ресурси валидни за цялото приложение

До тук сме съхранявали ресурси на ниво прозорец, което означава, че имате достъп до тях независимо къде от целия прозорец и само от него.

Ако имате нужда от даден ресурс само за конкретна контрола, можете да го направите още по-локален, като го добавите към тази конкретна контрола, вместо към прозореца. Работи по абсолютно същия начин, като единствената разлика е, че сега имате достъп само на нивото на контролата, където сте го поставили:

<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, което може да бъде полезно в няколко ситуации. В предишния пример видяхме как можем да съхраняваме ресурси на няколко различни места, така че в този пример ще имаме достъп до трите различни ресурса от 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:

<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());
		}
	}
}

И така, както можете да видите, ние съхраняваме три различни „Hello, world!" съобщения: Едно в App.xaml, едно на ниво прозорец и едно локално за главния панел. Интерфейсът се състои от бутон и ListBox.

В Code-behind обработваме събитието за кликване на бутона, в което добавяме всеки от текстовите низове към ListBox, както се вижда на екранната снимка. Използваме метода FindResource(), който ще върне ресурса като обект (ако бъде намерен), след което го превръщаме в низ, който знаем, че е чрез метода ToString().

Забележете как използваме метода FindResource() с различни обхвати - първо в панела, след това в прозореца и след това в текущия обект Application. Има смисъл да търсим ресурса там, където знаем, че е, но както вече споменахме, ако даден ресурс не бъде намерен на едно ниво, търсенето продължава нагоре по йерархията, така че по принцип бихме могли да използваме метода FindResource() на панела и в трите случая, тъй като ако не беше намерено на съответното ниво, щеше да се качи да търси на нивото на прозореца и по-късно на нивото на приложението.

Същото не важи на обратно - търсенето не навигира надолу по дървото, така че не можете да започнете да търсите ресурс на ниво приложение, ако е дефиниран локално за контрола или за прозореца.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!