Visão geral dos recursos XAML (WPF .NET)

Um recurso é um objeto que pode ser reutilizado em diferentes locais em seu aplicativo. Exemplos de recursos incluem pincéis e estilos. Esta visão geral descreve como usar recursos em XAML (Extensible Application Markup Language). Você também pode criar e acessar recursos usando código.

Observação

Os recursos XAML descritos neste artigo são diferentes dos recursos do aplicativo, que geralmente são arquivos adicionados a um aplicativo, como conteúdo, dados ou arquivos incorporados.

Importante

A documentação do Guia da Área de Trabalho para .NET 7 e .NET 6 está em construção.

Usar recursos em XAML

O exemplo a seguir define um como um SolidColorBrush recurso no elemento raiz de uma página. Em seguida, o exemplo faz referência ao recurso e o usa para definir propriedades de vários elementos filho, incluindo um , a TextBlocke um .EllipseButton

<Window x:Class="resources.ResExample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ResExample" Height="400" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="#05E0E9"/>
        <Style TargetType="Border">
            <Setter Property="Background" Value="#4E1A3D" />
            <Setter Property="BorderThickness" Value="5" />
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0.0" Color="#4E1A3D"/>
                        <GradientStop Offset="1.0" Color="Salmon"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="TextBlock" x:Key="TitleText">
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="Foreground" Value="#4E87D4"/>
            <Setter Property="FontFamily" Value="Trebuchet MS"/>
            <Setter Property="Margin" Value="0,10,10,10"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="Label">
            <Setter Property="HorizontalAlignment" Value="Right"/>
            <Setter Property="FontSize" Value="13"/>
            <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>
    </Window.Resources>

    <Border>
        <StackPanel>
            <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
            <TextBlock Style="{StaticResource Label}">Label</TextBlock>
            <TextBlock HorizontalAlignment="Right" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
            <Button HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
            <Ellipse HorizontalAlignment="Center" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="10" />
        </StackPanel>
    </Border>

</Window>

Cada elemento de nível de estrutura (FrameworkElement ou FrameworkContentElement) tem uma Resources propriedade, que é um ResourceDictionary tipo que contém recursos definidos. Você pode definir recursos em qualquer elemento, como um Buttonarquivo . No entanto, os recursos são mais frequentemente definidos no elemento raiz, que está Window no exemplo.

Cada recurso em um dicionário de recursos deve ter uma chave exclusiva. Ao definir recursos na marcação, atribua a chave exclusiva por meio da Diretiva x:Key. Normalmente, a chave é uma cadeia de caracteres; no entanto, você pode também a definir com outros tipos de objeto usando as extensões de marcação apropriadas. As chaves que não são de cadeia de caracteres para recursos são usadas por determinadas áreas de recursos no WPF, principalmente para estilos, recursos de componentes e estilo de dados.

Você pode usar um recurso definido com a sintaxe de extensão de marcação de recurso que especifica o nome da chave do recurso. Por exemplo, use o recurso como o valor de uma propriedade em outro elemento.

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

No exemplo anterior, quando o carregador XAML processa o valor {StaticResource MyBrush} da propriedade em Button, a lógica de pesquisa de recursos primeiro verifica o dicionário de recursos para o Button elementoBackground. Se Button não tiver uma definição da chave MyBrush de recurso (nesse exemplo, ela não tem; sua coleção de recursos está vazia), a pesquisa verificará em seguida o elemento pai de Button. Se o recurso não estiver definido no pai, ele continuará a verificar a árvore lógica do objeto para cima até que ele seja encontrado.

Se você definir recursos no elemento raiz, todos os elementos na árvore lógica, como o Window ou Page, poderão acessá-lo. E você pode reutilizar o mesmo recurso para definir o valor de qualquer propriedade que aceite o mesmo tipo que o recurso representa. No exemplo anterior, o mesmo MyBrush recurso define duas propriedades diferentes: Button.Background e Ellipse.Fill.

Recursos estáticos e dinâmicos

Um recurso pode ser referenciado como estático ou dinâmico. As referências são criadas usando a extensão StaticResource Markup ou a extensão de marcação DynamicResource. Uma extensão de marcação é um recurso XAML que permite especificar uma referência de objeto fazendo com que a extensão de marcação processe a cadeia de caracteres de atributo e retorne o objeto a um carregador XAML. Para obter mais informações sobre o comportamento da extensão de marcação, consulte Extensões de marcação e o XAML do WPF.

Quando você usa uma extensão de marcação, você normalmente fornece um ou mais parâmetros em forma de cadeia de caracteres que são processados por essa extensão de marcação específica. A Extensão de marcação de StaticResource processa uma chave procurando o valor dessa chave em todos os dicionários de recursos disponíveis. O processamento acontece durante a carga, que é quando o processo de carregamento precisa atribuir o valor da propriedade. Em vez disso, a Extensão de Marcação DynamicResource processa uma chave criando uma expressão, e essa expressão permanece não avaliada até que o aplicativo seja executado, momento em que a expressão é avaliada para fornecer um valor.

Quando você referencia um recurso, as seguintes considerações podem influenciar se uma referência de recurso estático ou dinâmico será usada:

  • Ao determinar o design geral de como você cria os recursos para seu aplicativo (por página, no aplicativo, em XAML solto ou em um assembly somente de recursos), considere o seguinte:

  • A funcionalidade do aplicativo. A atualização de recursos em tempo real faz parte dos requisitos do seu aplicativo?

  • O respectivo comportamento de pesquisa desse tipo de referência de recurso.

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

Recursos estáticos

As referências de recursos estáticos funcionam melhor nas seguintes circunstâncias:

  • O design do aplicativo concentra a maioria de seus recursos em dicionários de recursos no nível da página ou do aplicativo.

    As referências de recursos estáticos não são reavaliadas com base em comportamentos de tempo de execução, como recarregar uma página. Portanto, pode haver algum benefício de desempenho em evitar um grande número de referências de recursos dinâmicos quando elas não são necessárias com base no design do recurso e do aplicativo.

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

  • Você está criando um dicionário de recursos que é compilado em uma DLL compartilhada entre aplicativos.

  • Você está criando um tema para um controle personalizado e está definindo recursos que são usados dentro dos temas.

    Para esse caso, você normalmente não deseja o comportamento de pesquisa de referência de recurso dinâmico. Em vez disso, use o comportamento de referência de recurso estático para que a pesquisa seja previsível e autocontida para o tema. Com uma referência de recurso dinâmico, até mesmo uma referência dentro de um tema é deixada sem avaliação até o tempo de execução. E, há uma chance de que, quando o tema for aplicado, algum elemento local redefina uma chave que seu tema está tentando referenciar, e o elemento local cairá antes do próprio tema na pesquisa. Se isso acontecer, seu tema não se comportará como esperado.

  • Você está usando recursos para definir um grande número de propriedades de dependência. As propriedades de dependência têm cache de valor efetivo conforme habilitado pelo sistema de propriedades, portanto, se você fornecer um valor para uma propriedade de dependência que possa ser avaliada no momento do carregamento, a propriedade de dependência não precisará verificar se há uma expressão reavaliada e poderá retornar o último valor efetivo. Essa técnica pode ser uma vantagem de desempenho.

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

Comportamento de pesquisa de recursos estáticos

A seguir descreve o processo de pesquisa que acontece automaticamente quando um recurso estático é referenciado por uma propriedade ou elemento:

  1. O processo de pesquisa verifica a chave solicitada no dicionário de recursos definido pelo elemento que define a propriedade.

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

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

As referências de recursos estáticos em um dicionário de recursos devem referenciar um recurso que já foi definido lexicalmente antes da referência ao recurso. As referências de encaminhamento não podem ser resolvidas por uma referência de recursos estáticos. Por esse motivo, projete sua estrutura de dicionário de recursos de forma que os recursos sejam definidos no início de cada respectivo dicionário de recursos ou próximo a ele.

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

O comportamento de exceção se uma referência de recurso estático não for encontrada varia. Se o recurso foi adiado, a exceção ocorre em runtime. Se o recurso não foi adiado, a exceção ocorre no momento do carregamento.

Recursos dinâmicos

Os recursos dinâmicos funcionam melhor quando:

  • O valor do recurso, incluindo recursos do sistema ou recursos que são configuráveis pelo usuário, depende de condições que não são conhecidas até o tempo de execução. Por exemplo, você pode criar valores setter que se referem às propriedades do sistema como expostas por SystemColors, SystemFontsou SystemParameters. Esses valores são realmente dinâmicos, pois, basicamente, são obtidos do ambiente em runtime do usuário e do sistema operacional. Você também pode ter temas em nível do aplicativo que podem ser alterados, em que o acesso aos recursos em nível de página também deve captar a alteração.

  • Você está criando ou fazendo referência a estilos de tema para um controle personalizado.

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

  • Você tem uma estrutura de recursos complicada que tem interdependências, em que uma referência de encaminhamento pode ser necessária. As referências de recursos estáticos não oferecem suporte a referências diretas, mas as referências de recursos dinâmicos oferecem suporte a elas porque o recurso não precisa ser avaliado até o tempo de execução e, portanto, as referências de encaminhamento não são um conceito relevante.

  • Você está fazendo referência a um recurso que é grande da perspectiva de uma compilação ou conjunto de trabalho, e o recurso pode não ser usado imediatamente quando a página é carregada. As referências de recursos estáticos sempre são carregadas a partir de XAML quando a página é carregada. No entanto, uma referência de recurso dinâmico não é carregada até que seja usada.

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

  • Você está aplicando recursos a elementos que podem ser criados novamente na árvore lógica durante a vida útil do aplicativo. Potencialmente, a alteração do pai também altera o escopo de pesquisa de recursos; portanto, se você desejar que o recurso de um elemento reassociado seja reavaliado com base no novo escopo, sempre use uma referência de recursos dinâmicos.

Comportamento de pesquisa de recursos dinâmicos

O comportamento de pesquisa de recursos para uma referência de recurso dinâmico é paralelo ao comportamento de pesquisa em seu código se você chamar FindResource ou SetResourceReference:

  1. A pesquisa verifica a chave solicitada no dicionário de recursos definido pelo elemento que define a propriedade:

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

  3. Os recursos do aplicativo são verificados. Recursos de aplicativo são aqueles recursos dentro do dicionário de recursos que são definidos pelo Application objeto para seu aplicativo WPF.

  4. O dicionário de recursos de tema é verificado para o tema ativo no momento. Se o tema for alterado em runtime, o valor será reavaliado.

  5. Os recursos do sistema são verificados.

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

  • Se um recurso foi solicitado por uma chamada e não foi encontrado, uma FindResource exceção será lançada.

  • Se um recurso foi solicitado por uma TryFindResource chamada e não foi encontrado, nenhuma exceção será lançada e o valor retornado será null. Se a propriedade que está sendo definida não aceitar null, ainda é possível que uma exceção mais profunda seja lançada, dependendo da propriedade individual que está sendo definida.

  • Se um recurso foi solicitado por uma referência de recurso dinâmico em XAML e não foi encontrado, o comportamento depende do sistema de propriedades gerais. O comportamento geral é como se nenhuma operação de configuração de propriedade ocorresse no nível em que o recurso existe. Por exemplo, se você tentar definir o plano de fundo em um elemento de botão individual usando um recurso que não pôde ser avaliado, nenhum conjunto de valores resultará, mas o valor efetivo ainda poderá vir de outros participantes do sistema de propriedades e da precedência de valor. Por exemplo, o valor de 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 avaliação de recurso com falha pode vir do valor padrão nos metadados da propriedade.

Restrições

As referências de recursos dinâmicos têm algumas restrições importantes. Pelo menos uma das seguintes condições deve ser verdadeira:

Como a propriedade que está sendo definida deve ser uma propriedade ouFreezable, a maioria das alterações de propriedade pode se propagar para a interface do usuário porque uma DependencyProperty alteração de propriedade (o valor do recurso dinâmico alterado) é reconhecida pelo sistema de propriedades. A maioria dos controles inclui lógica que forçará outro layout de um controle se uma DependencyProperty alteração e essa propriedade puderem afetar o layout. No entanto, nem todas as propriedades que têm uma extensão de marcação DynamicResource como seu valor são garantidas para fornecer atualizações em tempo real na interface do usuário. Essa funcionalidade ainda pode variar dependendo da propriedade e dependendo do tipo que possui a propriedade ou até mesmo da estrutura lógica do seu aplicativo.

Estilos, DataTemplates e chaves implícitas

Embora todos os itens em um devem ter uma chave, isso não significa que todos os recursos devem ter um ResourceDictionaryx:Keyarquivo . Vários tipos de objeto dão suporte a uma chave implícita quando definidos como um recurso, em que o valor da chave é vinculado ao valor de outra propriedade. Esse tipo de chave é conhecido como uma chave implícita e um x:Key atributo é uma chave explícita. Você pode substituir uma chave implícita especificando uma chave explícita.

Um cenário importante para recursos é quando você define um Stylearquivo . Na verdade, a é quase sempre definido como uma entrada em um dicionário de recursos, porque os Style estilos são inerentemente destinados à reutilização. Para obter mais informações sobre estilos, consulte Estilos e modelos (WPF .NET).

Os estilos de controles podem ser criados com uma chave implícita e referenciados com ela. Os estilos de tema que definem a aparência padrão de um controle se baseiam nessa chave implícita. Do ponto de vista de solicitá-lo, a chave implícita é a Type do próprio controle. Do ponto de vista da definição dos recursos, a chave implícita é a TargetType do estilo. Dessa forma, se você estiver criando temas para controles personalizados ou criando estilos que interajam com estilos de tema existentes, não será necessário especificar uma Diretiva x:Key para isso Style. E se você quiser usar os estilos temáticos, não precisará especificar nenhum estilo. Por exemplo, a definição de estilo a seguir funciona, mesmo que o Style recurso não pareça ter uma chave:

<Style TargetType="Button">
    <Setter Property="Background" Value="#4E1A3D" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="BorderThickness" Value="5" />
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush>
                <GradientStop Offset="0.0" Color="#4E1A3D"/>
                <GradientStop Offset="1.0" Color="Salmon"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

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

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 próprio não tente especificar sua Style propriedade ou uma referência de recurso específico para o Button estilo. Seu estilo definido na página é encontrado anteriormente na sequência de pesquisa do que o estilo de dicionário de tema, usando a mesma chave que o estilo de dicionário de tema. Você poderia apenas especificar <Button>Hello</Button> em qualquer lugar da página, e o estilo que você definiu com TargetType de Button se aplicaria a esse botão. Se desejar, você ainda pode digitar explicitamente o estilo com o mesmo valor de tipo que TargetType para clareza em sua marcação, mas isso é opcional.

As chaves implícitas para estilos não se aplicam a um controle se OverridesDefaultStyle for true. (Observe também que OverridesDefaultStyle pode ser definido como parte do comportamento nativo para a classe de 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 classe derivada, o controle deve substituir DefaultStyleKey (todos os controles existentes fornecidos como parte do WPF incluem essa substituição). Para obter mais informações sobre estilos, temas e design de controle, consulte Diretrizes para a criação de controles estilizados.

DataTemplate também tem uma chave implícita. A chave implícita para a DataTemplate é o valor da DataType propriedade. DataType também pode ser especificado como o nome do tipo em vez de usar explicitamente {x:Type...}. Para obter detalhes, consulte Visão geral da modelagem de dados.

Confira também