Visão geral sobre Recursos

Esta visão geral explica como usar recursos WPF como uma maneira simples de reutilizar objetos e valores comumente definidos. Esta visão geral se concentra em como usar recursos em XAML. Você também pode criar e acessar recursos por meio de código, ou de forma intercambiável entre código e Extensible Application Markup Language (XAML). Para obter mais informações, consulte Recursos e código.

Este tópico contém as seguintes seções.

  • Usando recursos em XAML
  • Recursos estáticos e dinâmicos
  • Estilos, DataTemplates e chaves implícitas
  • Tópicos relacionados

Usando recursos em XAML

O exemplo a seguir define um SolidColorBrush como um recurso no elemento raiz de uma página. O exemplo, em seguida, referencia o recurso e o usa para definir as propriedades de vários elementos filho, incluindo uma Ellipse, um TextBlock e um Button.

<Page Name="root"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
  <Page.Resources>
    <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
    <Style TargetType="Border" x:Key="PageBackground">
      <Setter Property="Background" Value="Blue"/>
    </Style>
    <Style TargetType="TextBlock" x:Key="TitleText">
      <Setter Property="Background" Value="Blue"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="FontSize" Value="18"/>
      <Setter Property="Foreground" Value="#4E87D4"/>
      <Setter Property="FontFamily" Value="Trebuchet MS"/>
      <Setter Property="Margin" Value="0,40,10,10"/>
    </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"/>
    </Style>
  </Page.Resources>
  <StackPanel>
    <Border Style="{StaticResource PageBackground}">
      <DockPanel>
        <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
        <TextBlock Style="{StaticResource Label}">Label</TextBlock>
        <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
        <Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
        <Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
      </DockPanel>
    </Border>
  </StackPanel>
</Page>


Cada elemento no nível do framework (FrameworkElement ou FrameworkContentElement) tem uma propriedade Resources, que é a propriedade que contém os recursos (como um ResourceDictionary) que um recurso define. Você pode definir recursos em qualquer elemento. No entanto, recursos são com mais frequência definidos no elemento raiz, que é uma Page no exemplo.

Cada recurso em um dicionário de recursos deve ter uma chave exclusiva. Quando você define recursos em marcação, atribua a chave exclusiva por meio de Atributo x:Key. Normalmente, a chave é uma sequência de caracteres; no entanto, você também pode definí-la com outros tipos de objeto utilizando as extensões de marcação apropriadas. Chaves não string para recursos são usadas por determinadas áreas de recursos no WPF, especialmente em estilos, recursos de componente e estilização de dados.

Após você definir um recurso, você pode referenciá-lo para ser usado em um valor de propriedade, usando uma sintaxe de extensão de marcação de recursos que especifica o nome da chave, por exemplo:

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

No exemplo anterior, quando o carregador de XAML processa o valor {StaticResource MyBrush} da propriedade Background no Button, a lógica de pesquisa por recursos primeiro verifica o dicionário de recursos do elemento Button. Se Button não tem uma definição da chave de recurso MyBrush (ele não tem; sua coleção de recursos está vazia), a pesquisa em seguida verifica o elemento pai do Button, que é a Page. Assim, quando você definir um recurso no elemento raiz Page, todos os elementos na árvore lógica da Page podem acessá-lo, e você poderá reutilizar o mesmo recurso para definir o valor de qualquer propriedade que aceita o Type que o recurso representa. No exemplo anterior, o mesmo MyBrush recurso define duas propriedades diferentes: the Background de um Buttone o Fill de um Rectangle.

Recursos estáticos e dinâmicos

Um recurso pode ser referenciado como um recurso estático ou como um recurso dinâmico. Isso é concluído usando ambos o Extensão de marcação StaticResource ou o Extensão de marcação DynamicResource. Uma extensão de marcação é um recurso de XAML onde você pode especificar uma referência de objeto, fazendo com que a extensão de marcação processe a sequência de caracteres do atributo e retorne o objeto para um carregador de XAML. Para obter mais informações sobre o comportamento de extensões de marcação, consulte Extensão de Marcação e XAML.

Quando você usa uma extensão de marcação, você normalmente fornece um ou mais parâmetros na forma de sequência de caracteres que são processadas pela extensão de marcação determinada, em vez de serem avaliadas no contexto da propriedade sendo definida. A Extensão de marcação StaticResource processa uma chave pesquisando o valor para essa chave em todos os dicionários de recursos disponíveis. Isso acontece durante o carregamento, que é o ponto no tempo quando o processo carregador precisa atribuir a valor da propriedade que recebe a referência a recurso estático. A Extensão de marcação DynamicResource, em vez disso, processa uma chave criando uma expressão, e essa expressão permanece não avaliada até que o aplicativo está realmente sendo executado, só então a expressão é avaliada e fornece um valor.

Quando você referencia um recurso, as considerações a seguir podem influenciar se você deve usar uma referência a recurso estático ou uma referência a recurso dinâmico:

  • O projeto geral de como você cria os recursos para seu aplicativo (por página, no aplicativo, em XAML livre, em um conjunto de módulos somente de recursos).

  • A funcionalidade do aplicativo: está atualizando recursos em time real de parte de seus requisitos de aplicativos?

  • Os respectivos comportamentos de pesquisa do tipo de referência a recursos.

  • A propriedade ou o tipo de recurso específicos e o comportamento nativo desses tipos.

Recursos estáticos

Referências a recursos estáticos funcionam melhor nas seguintes circunstâncias:

  • O seu projeto de aplicativo concentra a maioria dos seus recursos em dicionários de recursos em nível de página ou de aplicativo. Referências a recursos estáticos não são reavaliadas com base em comportamentos em tempo de execução como recarregar uma página, e, portanto, pode haver algum benefício de desempenho em evitar um grande número de referências a recursos dinâmicos quando elas não são necessárias no seu projeto de recursos e de aplicativo.

  • Você está definindo o valor de uma propriedade que não está em um DependencyObject ou em um Freezable.

  • Você está criando um dicionário de recursos que será compilado em uma DLL e empacotado como parte do aplicativo ou compartilhado entre aplicativos.

  • Você está criando um tema para uma controle personalizado e está definindo recursos que são usados dentro dos temas. Neste caso, normalmente não se deseja o comportamento de pesquisa de referências a recursos dinâmicos, em vez disso, se deseja o comportamento de referências a recursos estáticos para que a pesquisa seja previsível e autocontida com relação ao tema. Com uma referência a um recurso dinâmico, até mesmo uma referência em um tema é deixada como não avaliada até tempo de execução, e há uma chance de que quando o tema for aplicado, algum elemento local vá redefinir alguma chave que o seu tema tenta referenciar, e o elemento local cairá antes do próprio tema na ordem da pesquisa. Se isso acontecer, seu tema não irá se comportar da maneira esperada.

  • Você está usando recursos para definir um grande número de propriedades de dependência. As propriedades de dependência têm cache de seus valores efetivos propiciada pelo sistema de propriedades, então se você fornecer um valor para um propriedade de dependência que pode ser avaliado em tempo de carregamento, a propriedade de dependência não precisa procurar uma expressão reavaliada e pode retornar o último valor efetivo. Essa técnica pode trazer um benefício de desempenho.

  • Para alterar o recurso subjacente para todos os consumidores ou você deseja manter instâncias graváveis separadas para cada consumidor usando o Atributo x:Shared.

Comportamento de pesquisa de recursos estáticos

  1. O processo de pesquisa procura a chave solicitada dentro do dicionário de recursos definido pelo elemento que define a propriedade.

  2. O processo de pesquisa, em seguida, percorre a árvore lógica para cima, para o elemento pai e seu dicionário de recursos. Esse procedimento continua até que o elemento raiz seja alcançado.

  3. Em seguida, os recursos de aplicativo são verificados. Recursos de aplicativo são aqueles recursos dentro do dicionário de recursos que é definido pelo objeto Application para o seu aplicativo WPF.

Referências a recursos estáticos dentro de um dicionário de recursos devem fazer referência a um recurso que já tenha sido definido lexicalmente antes da referência ao recurso. Referências para frente não podem ser resolvidas por uma referência a recurso estático. Por esse motivo, se você usar referências a recursos estáticos, você deve projetar a estrutura do dicionário de recursos de modo que recursos destinados ao uso por recursos sejam definidos no (ou próximo do) início de cada respectivo dicionário de recursos.

A pesquisa por recursos estáticos pode se estender a temas, ou a recursos do sistema, mas isso é suportado apenas porque o carregador de XAML posterga a solicitação. A postergação é necessária para que o tema em tempo de execução se aplique corretamente ao aplicativo no momento em que a página for carregada. No entanto, referências de recursos estáticos a chaves que são conhecidas por existir somente em temas ou como recursos de sistema não são recomendadas. Isso ocorre porque essas referências não são reavaliadas se o tema for alterado pelo usuário em tempo real. Uma referência a recurso dinâmico é mais confiável quando você solicitar recursos de temas ou do sistema. A exceção é quando um elemento tema solicita ele mesmo um outro recurso. Essas referências devem ser referências a recursos estáticos, pelas razões mencionadas anteriormente.

O comportamento de exceção se uma referência a recurso estático não for encontrada varia. Se o recurso foi postergado, então a exceção ocorre em tempo de execução. Se o recurso não foi postergado, a exceção ocorre em tempo de carregamento.

Recursos dinâmicos

Recursos dinâmicos funcionam melhor para as seguintes circunstâncias:

  • O valor do recurso depende de condições que não são conhecidas até em tempo de execução. Isso inclui recursos do sistema ou recursos que sejam de alguma outra forma configuráveis pelo usuário. Por exemplo, você pode criar valores setter que fazem referência a propriedades do sistema, como expostos por SystemColors, SystemFonts ou SystemParameters. Esses valores são realmente dinâmicos pois eles basicamente são provenientes do ambiente em tempo de execução do usuário e do sistema operacional. Você também pode ter temas em nível de aplicativo que podem ser alterados, onde o acesso a recursos no nível da página também deve captar a alteração.

  • Você está criando ou referenciando estilos de tema para um controle personalizado.

  • Você pretende ajustar o conteúdo de um ResourceDictionary durante o ciclo de vida do aplicativo.

  • Você tem uma estrutura complexa de recursos que tenha interdependências, onde uma referência para frente pode ser necessária. Referências a recursos estáticos não têm suporte a referências para frente, mas referências a recursos dinâmicos oferecem suporte a isso pois o recurso não precisa ser avaliado até a execução, e, portanto, referências para frente não é um conceito relevante.

  • Você está referenciando um recurso que é especialmente grande da perspectiva de um conjunto de trabalho ou de compilação; e o recurso pode não ser usado imediatamente quando a página for carregada. Referências a recursos estáticos sempre são carregadas do XAML quando a página for carregada; no entanto, uma referência a recurso dinâmico não é carregada até que ela realmente seja usado.

  • Você está criando um estilo onde valores setter podem vir de outros valores que são influenciados por temas ou outras configurações de usuário.

  • Você está aplicando recursos a elementos que podem ter seus pais modificados na árvore lógica durante o ciclo de vida do aplicativo. Alterar o pai também potencialmente altera o escopo de pesquisa de recursos, então se você deseja que o recurso para um elemento que pode ter o pai mudado seja reavaliado com base no novo escopo, sempre use uma referência a recurso dinâmico.

Comportamento de pesquisa de recursos dinâmicos

O comportamento de pesquisa por um recurso dinâmico funciona de forma paralela ao comportamento de pesquisa no seu código se você chamar FindResource ou SetResourceReference.

  1. O processo de pesquisa procura a chave solicitada dentro do dicionário de recursos definido pelo elemento que define a propriedade.

  2. O processo de pesquisa, em seguida, percorre a árvore lógica para cima, para o elemento pai e seu dicionário de recursos. Esse procedimento continua até que o elemento raiz seja alcançado.

  3. Em seguida, os recursos de aplicativo são verificados. Recursos de aplicativo são aqueles recursos dentro do dicionário de recursos que é definido pelo objeto Application para o seu aplicativo WPF.

  4. O dicionário de recursos de tema é checado, para o tema ativo no momento. Se o tema for alterado em tempo de execução, o valor é reavaliado.

  5. Recursos do sistema são verificados.

O comportamento de exceção (se houver) varia:

  • Se um recurso foi solicitado por uma chamada a FindResource e não foi encontrado, uma exceção é gerada.

  • Se um recurso foi solicitado por uma chamada a TryFindResource e não foi encontrado, nenhuma exceção é gerada, mas o valor retornado é null. Se a propriedade sendo definida não aceita null, então ainda é possível que uma exceção mais profunda seja gerada (isso depende da propriedade que está sendo definida).

  • Se um recurso foi solicitado por uma referência de recurso dinâmico em XAML e não foi encontrado, então o comportamento depende do sistema de propriedade geral, mas o comportamento geral é como se nenhuma operação de configuração de propriedade ocorreu no nível onde o recurso existe. Por exemplo, se você tentar definir o plano de fundo em um um elemento Button específico usando um recurso que não pôde ser avaliado, então nenhum valor é definido, mas o valor efetivo ainda pode vir de outros participantes no sistema de propriedades e precedência de valores. Por exemplo, o valor do plano de fundo ainda pode vir de um estilo de botão definido localmente, ou do estilo de tema. Para propriedades que não são definidas por estilos de tema, o valor efetivo após uma falha de avaliação de recurso pode vir do valor padrão nos metadados da propriedade.

Restrições

Referências a recursos dinâmicos têm algumas restrições perceptíveis. Pelo menos um destes itens deve ser verdadeiro:

Como a propriedade sendo definida deve ser uma DependencyProperty ou uma propriedade de Freezable, a maioria das alterações em propriedades podem se propagar até a interface do usuário pois uma alterações de propriedade (o valor alterado do recurso dinâmico) é reconhecida pelo sistema de propriedades. A maioria dos controles incluem lógica que forçará outro layout de um controle se uma DependencyProperty é alterada e essa propriedade puder afetar o layout. No entanto, nem todas as propriedades que têm uma Extensão de marcação DynamicResource como valor garantem o fornecimento do valor de tal forma que elas sejam atualizadas em tempo real na interface do usuário. Essa funcionalidade ainda pode variar de acordo com a propriedade, bem como dependendo do tipo que possui a propriedade, ou até mesmo a estrutura lógica do seu aplicativo.

Estilos, DataTemplates e chaves implícitas

Anteriormente foi mencionado que todos os itens em um ResourceDictionary devem ter uma chave. No entanto, isso não significa que todos os recursos devem ter uma x:Key explícita. Vários tipos de objeto oferecem suporte a uma chave implícita quando definidos como recursos, onde o valor da chave está vinculado ao valor de outra propriedade. Isso é conhecido como uma chave implícita, enquanto um atributo x:Key é uma chave explícita. Você pode sobrescrever qualquer chave implícita especificando uma chave explícita.

Uma situação muito importante para recursos é quando você define um Style. Na verdade, um Style quase sempre é definido como uma entrada em um dicionário de recursos, porque estilos são inerentemente destinados a reuso. Para obter mais informações sobre estilos, consulte Styling and Templating.

Estilos de controles podem ser tanto criados como referenciados com uma chave implícita. Os estilos de tema que definem a aparência padrão de um controle dependem dessa chave implícita. A chave implícita, do ponto de vista de solicitá-la, o Type do controle propriamente dito. A chave implícita, do ponto de vista da definição do recurso, é o TargetType do estilo. Portanto, se você estiver criando temas para controles personalizados, criando estilos que interagem com estilos de tema existentes, você não precisará especificar um Atributo x:Key para esse Style. E se você quiser usar os estilos com tema, você não precisa especificar qualquer estilo. Por exemplo, a seguinte definição de estilo funciona, mesmo que o recurso Style não pareça ter uma chave:

<Style TargetType="Button">
  <Setter Property="Background">
    <Setter.Value>
      <LinearGradientBrush>
        <GradientStop Offset="0.0" Color="AliceBlue"/>
        <GradientStop Offset="1.0" Color="Salmon"/>           
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>  
  <Setter Property="FontSize" Value="18"/>
</Style>

Esse estilo realmente tem uma chave: a chave implícita typeof(Button). Em marcação, você pode especificar um TargetType diretamente como nome do tipo (ou, opcionalmente, você pode usar {x:Type...} para retornar um Type).

Por meio dos mecanismos de estilo de tema padrão usados pelo WPF, esse estilo é aplicado como o estilo de tempo de execução de um Button na página, mesmo que o Button não tente especificar sua propriedade Style ou uma referência de recursos específica para o estilo. Seu estilo definido na página é encontrado na sequência de pesquisa antes do estilo de dicionário de temas, usando a mesma chave que tem o estilo de dicionário de temas. Você poderia apenas especificar <Button>Hello</Button> em qualquer lugar na página e o estilo definido com TargetType igual Button seria aplicado a esse botão. Se você desejar, você ainda pode explicitamente definir uma chave para o estilo com o mesmo valor de tipo que TargetType, para fins de claridade em sua marcação, mas isto é opcional.

Chaves implícitas para estilos não se aplicam em um controle se OverridesDefaultStyle for true (observe também que OverridesDefaultStyle talvez esteja definido como parte do comportamento nativo para a classe do controle, em vez de explicitamente em uma instância do controle). Além disso, para oferecer suporte a chaves implícitas para cenários de classes derivadas, o controle deve sobrescrever DefaultStyleKey (todos os controles existentes fornecidos como parte do WPF fazem isso). Para obter mais informações sobre estilos, temas e projeto de controles, consulte Diretrizes para criação de controles estilizados.

DataTemplate também tem uma chave implícita. A chave implícita para um DataTemplate é o DataType valor da propriedade. DataType também pode ser especificado sistema autônomo o nome do tipo em vez de explicitamente usando {x: tipo...}. Para obter detalhes, consulte:Visão geral sobre Templating de dados.

Consulte também

Tarefas

Como: Definir e referenciar um recurso

Conceitos

Otimizando o desempenho: Recursos do aplicativo

Recursos e código

Visão Geral do Gerenciamento de Aplicativo

Referência

Marcação de Extensão x:Type

ResourceDictionary

Extensão de marcação StaticResource

Extensão de marcação DynamicResource