This article has been localized into Portuguese by the community.
Resources
O WPF introduziu um conceito muito conveniente: A capacidade de guardar dados como um recurso (resource), seja localmente para um controle, localmente para uma janela inteira ou globalmente para a aplicação inteira. Os dados podem ser praticamente o que você quiser, desde informações reais até uma hierarquia de controles do WPF. Isso permite que você coloque dados em um lugar e, em seguida, use-os de ou vários outros lugares, o que é muito útil.
O conceito é muito usado para styles e templates, que discutiremos mais adiante neste tutorial, mas como será ilustrado neste capítulo, você também pode usá-los para muitas outras coisas. Permita-me demonstrar isso com um exemplo simples:
<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>
Os recursos recebem uma chave, usando o atributo x:Key, que te permite referenciá-lo de outras partes da aplicação usando essa chave, combinando com a extensão de marcação StaticResource. Neste exemplo, eu apenas armazeno uma string simples, que eu uso a partir de dois controles TextBlock diferentes.
StaticResource vs. DynamicResource
Nos exemplos até agora, usei a extensão de marcação StaticResource para fazer referência a um recurso. No entanto, existe uma alternativa na forma do DynamicResource.
A principal diferença é que um recurso estático é resolvido apenas uma vez, que é no momento em que o XAML é carregado. Se o recurso for alterado posteriormente, esta alteração não será refletida onde você usou o StaticResource.
Um recurso dinâmico (DynamicResource), por outro lado, é resolvido assim que realmente for necessário e, em seguida, novamente, se o recurso for alterado. Pense nisso como um vínculo a um valor estático vs. vínculo a uma função que monitora esse valor e envia para você cada vez que ele é alterado - não é exatamente como ele funciona, mas deve te dar uma ideia melhor de quando usar um ou outro. Os recursos dinâmicos também permitem que você use recursos que nem sequer existem durante o tempo de design, por exemplo, se você adicioná-los pelo code-behind durante a inicialização do aplicativo.
Mais tipos de resources
Compartilhar uma string simples foi fácil, mas você pode fazer muito mais. No próximo exemplo, também armazenarei uma matriz completa de strings, junto com um pincel de gradiente para ser usado no background. Isso deve lhe dar uma boa ideia de quanto você pode fazer com os recursos:
<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>
Desta vez, adicionamos alguns recursos extras, para que a nossa janela agora contenha uma string simples, uma matriz de strings e um LinearGradientBrush. A string é usada para o rótulo, o array de strings é usado como itens para o controle ComboBox e o pincel de gradiente é usado como plano de fundo para a janela toda. Então, como você pode ver, praticamente tudo pode ser armazenado como um recurso.
Resources locais e de aplicação
Por enquanto, armazenamos recursos em um nível de janela, o que significa que você pode acessá-los por toda a janela.
Se você precisar apenas de um determinado recurso para um controle específico, poderá torná-lo mais local adicionando-o a esse controle específico, em vez da janela. Funciona exatamente da mesma maneira, a única diferença é que agora você só pode acessar de dentro do escopo do controle onde você o colocou:
<StackPanel Margin="10">
<StackPanel.Resources>
<sys:String x:Key="ComboBoxTitle">Items:</sys:String>
</StackPanel.Resources>
<Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>
Nesse caso, adicionamos o recurso ao StackPanel e, em seguida, o usamos de seu controle filho, o Label. Outros controles dentro do StackPanel também poderiam ter usado, assim como os filhos desses controles poderiam acessá-lo. No entanto, controles fora deste StackPanel em particular não teriam acesso a ele.
Se você precisar acessar o recurso de várias janelas, isso também será possível. O arquivo App.xaml pode conter recursos assim como a janela e qualquer tipo de controle do WPF, e quando você os armazena no App.xaml, eles são globalmente acessíveis em todas as janelas e controles de usuário do o projeto. Funciona exatamente da mesma maneira que ao armazenar e usar de uma janela:
<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>
Usar ele também é a mesma coisa - O WPF subirá automaticamente o escopo do controle local para a janela e, em seguida, para App.xaml, para localizar um determinado resource:
<Label Content="{StaticResource ComboBoxTitle}" />
Resources do Code-behind
Até agora, acessamos todos os nossos resources diretamente do XAML, usando uma extensão de marcação. No entanto, é claro que você pode acessar seus resources do Code-behind também, o que pode ser útil em várias situações. No exemplo anterior, vimos como poderíamos armazenar resources em vários lugares diferentes, então neste exemplo, estaremos acessando três resources diferentes no Code-behind, cada um armazenado em um escopo diferente:
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());
}
}
}
Então, como você pode ver, nós armazenamos três mensagens "Hello, world!" diferentes: Uma em App.xaml, uma dentro da janela e uma localmente para o painel principal. A interface consiste em um botão e um ListBox.
No Code-behind, lidamos com o evento de clique do botão, no qual adicionamos cada uma das strings de texto ao ListBox, como visto na captura de tela. Usamos o método FindResource(), que retornará o recurso como um objeto (se encontrado), e então o transformaremos em string que sabemos que será usando o método ToString().
Note como usamos o método FindResource() em escopos diferentes - primeiro no painel, depois na janela e, em seguida, no objeto Application. Faz sentido procurar o recurso onde sabemos que ele está, mas como já mencionado, se um recurso não for encontrado, a pesquisa continua na hierarquia, portanto, a princípio, poderíamos ter usado o método FindResource() no painel em todos os três casos, já que ele teria continuado até a janela e, posteriormente, até o nível do aplicativo, se não for encontrado.
Por outro lado o contrário não é verdadeiro - a pesquisa não navega pela árvore de modo descendente, portanto, você não pode começar a procurar um recurso no nível do aplicativo, se tiver sido definido localmente para o controle ou para a janela.