Szukaj…
Cześć zasoby
WPF wprowadza bardzo przydatną koncepcję: możliwość przechowywania danych jako zasobu, albo lokalnie dla kontroli, lokalnie dla całego okna lub globalnie dla całej aplikacji. Dane mogą być dowolne, od rzeczywistych informacji po hierarchię elementów sterujących WPF. Umożliwia to umieszczenie danych w jednym miejscu, a następnie wykorzystanie ich z jednego lub kilku innych miejsc, co jest bardzo przydatne. Koncepcja ta jest często używana w przypadku stylów i szablonów.
<Window x:Class="WPFApplication.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>
Zasoby otrzymują klucz za pomocą atrybutu x: Key, który pozwala odwoływać się do niego z innych części aplikacji za pomocą tego klucza, w połączeniu z rozszerzeniem StaticResource. W tym przykładzie po prostu przechowuję prosty ciąg, który następnie używam z dwóch różnych kontrolek TextBlock.
Rodzaje zasobów
Udostępnianie prostego ciągu było łatwe, ale możesz zrobić znacznie więcej. W tym przykładzie będę również przechowywać pełną tablicę ciągów wraz z pędzlem gradientowym, który będzie używany jako tło. To powinno dać ci całkiem dobry pomysł na to, ile możesz zrobić z zasobami:
<Window x:Class="WPFApplication.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>
Tym razem dodaliśmy kilka dodatkowych zasobów, dzięki czemu nasze okno zawiera teraz prosty ciąg, tablicę ciągów i LinearGradientBrush. Ciąg jest używany jako etykieta, tablica ciągów jest używana jako elementy kontrolki ComboBox, a pędzel gradientowy jest używany jako tło dla całego okna. Jak więc widać, prawie wszystko może być przechowywane jako zasób.
Zasoby lokalne i dotyczące całej aplikacji
Jeśli potrzebujesz tylko danego zasobu dla określonej kontrolki, możesz uczynić ją bardziej lokalną, dodając ją do tej kontrolki zamiast do okna. Działa dokładnie w ten sam sposób, z tą różnicą, że można teraz uzyskać dostęp tylko z zakresu kontrolki, w której został umieszczony:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
W takim przypadku dodajemy zasób do StackPanel, a następnie używamy go z kontrolki podrzędnej, Label. Inne elementy sterujące w StackPanel również mogłyby z niego korzystać, podobnie jak dzieci tych elementów potomnych mogłyby uzyskać do niego dostęp. Jednak formanty poza tym konkretnym StackPanel nie miałyby do niego dostępu.
Jeśli potrzebujesz dostępu do zasobu z kilku okien, jest to również możliwe. Plik App.xaml może zawierać zasoby takie jak okno i dowolna kontrola WPF, a kiedy przechowujesz je w App.xaml, są one globalnie dostępne we wszystkich oknach i kontrolach użytkownika projektu. Działa dokładnie tak samo, jak podczas przechowywania i korzystania z okna:
<Application x:Class="WpfSamples.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="WPFApplication/ExtendedResourceSample.xaml">
<Application.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</Application.Resources>
</Application>
Korzystanie z niego jest również takie samo - WPF automatycznie przejdzie w górę zakresu, od lokalnego sterowania do okna, a następnie do App.xaml, aby znaleźć dany zasób:
<Label Content="{StaticResource ComboBoxTitle}" />
Zasoby od kodu
W tym przykładzie będziemy uzyskiwać dostęp do trzech różnych zasobów od kodu, każdy przechowywany w innym zakresie
App.xaml:
<Application x:Class="WpfSamples.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="WPFApplication/ResourcesFromCodeBehindSample.xaml">
<Application.Resources>
<sys:String x:Key="strApp">Hello, Application world!</sys:String>
</Application.Resources>
</Application>
Okno:
<Window x:Class="WpfSamples.WPFApplication.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>
Kod za:
using System;
using System.Windows;
namespace WpfSamples.WPFApplication
{
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());
}
}
}
Jak widać, przechowujemy trzy różne „Witaj, świecie!” wiadomości: jedna w App.xaml, jedna w oknie i jedna lokalnie dla panelu głównego. Interfejs składa się z przycisku i ListBox.
W Code-behind obsługujemy zdarzenie click przycisku, w którym dodajemy każdy ciąg tekstowy do ListBox, jak pokazano na zrzucie ekranu. Używamy metody FindResource (), która zwróci zasób jako obiekt (jeśli zostanie znaleziony), a następnie zamieniamy go na ciąg znaków, który znamy, za pomocą metody ToString ().
Zauważ, jak używamy metody FindResource () w różnych zakresach - najpierw w panelu, potem w oknie, a następnie w bieżącym obiekcie aplikacji. Sensowne jest poszukiwanie zasobu tam, gdzie go znamy, ale jak już wspomniano, jeśli zasób nie zostanie znaleziony, wyszukiwanie posuwa się w górę hierarchii, więc w zasadzie moglibyśmy użyć metody FindResource () na panelu w wszystkie trzy przypadki, ponieważ kontynuowałby do okna, a później do poziomu aplikacji, jeśli nie zostałby znaleziony.
To samo nie jest prawdą na odwrót - wyszukiwanie nie nawiguje w dół drzewa, więc nie możesz zacząć szukać zasobu na poziomie aplikacji, jeśli został on zdefiniowany lokalnie dla kontrolki lub okna.