Partilhar via


Visão geral dos recursos XAML

Um recurso é um objeto que pode ser reutilizado em diferentes locais no seu aplicativo. Exemplos de recursos incluem pincéis e estilos. Esta visão geral descreve como usar recursos em Extensible Application Markup Language (XAML). 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.

Usar recursos em XAML

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

<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, você atribui a chave exclusiva por meio da Diretiva x:Key. Normalmente, a chave é uma cadeia de caracteres; no entanto, você também pode defini-lo para outros tipos de objeto usando as extensões de marcação apropriadas. Chaves sem cadeia de caracteres para recursos são usadas por determinadas áreas de recursos no WPF, principalmente para estilos, recursos de componentes e estilos de dados.

Você pode usar um recurso definido com a sintaxe da 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 Background, a lógica de pesquisa de recursos primeiro verifica o dicionário de recursos em busca do Button elementoButton. Se Button não tiver uma definição da chave MyBrush de recurso (nesse exemplo, não; sua coleção de recursos está vazia), a pesquisa em seguida verificará 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 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 StaticResource Markup Extension ou a DynamicResource Markup Extension. 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 para um carregador XAML. Para obter mais informações sobre o comportamento da extensão de marcação, consulte Extensões de marcação e WPF XAML.

Quando você usa uma extensão de marcação, 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 StaticResource Markup Extension 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 DynamicResource Markup Extension 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ê faz referência a um recurso, as seguintes considerações podem influenciar se você usa uma referência de recurso estático ou uma referência de recurso dinâmico:

  • 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 respetivo comportamento de pesquisa desse tipo de referência de recurso.

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

Recursos estáticos

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

  • O design do seu 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 ao 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 seu recurso e aplicativo.

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

  • Você está criando um dicionário de recursos 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.

    Neste caso, não se costuma desejar o comportamento de consulta 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 independente para o tema. Com uma referência de recurso dinâmica, até mesmo uma referência dentro de um tema é mantida 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 caia 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. Esta técnica pode ser um benefício de desempenho.

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

Comportamento de pesquisa de recursos estáticos

A seguir descrevemos 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. Em seguida, o processo de 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 é definido pelo Application objeto para seu aplicativo WPF.

As referências de recursos estáticos de dentro de um dicionário de recursos devem fazer referência a um recurso que já tenha sido definido lexicamente antes da referência de recurso. As referências futuras não podem ser resolvidas por uma referência de recurso estático. Por esse motivo, projete sua estrutura de dicionário de recursos de modo que os recursos sejam definidos no início ou perto do início de cada dicionário de recursos respetivo.

A pesquisa de recursos estáticos pode se estender para temas ou recursos do sistema, mas essa pesquisa é suportada somente porque o carregador XAML adia a solicitação. O adiamento é necessário para que o tema de execução quando a página é carregada se aplique corretamente à aplicação. 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 de tema ou sistema. A exceção é quando um elemento de tema em si 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 tempo de execução. 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 conforme expostas por SystemColors, SystemFontsou SystemParameters. Esses valores são verdadeiramente dinâmicos porque, em última análise, vêm do ambiente de tempo de execução do usuário e do sistema operacional. Você também pode ter temas no nível do aplicativo que podem ser alterados, onde o acesso a recursos no nível da página também deve capturar 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 ResourceDictionary ao longo do tempo de vida de um aplicativo.

  • Você tem uma estrutura de recursos complicada que tem interdependências, onde uma referência direta pode ser necessária. As referências de recursos estáticos não suportam referências de encaminhamento, mas as referências de recursos dinâmicos as suportam 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 perspetiva 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 de XAML quando a página é carregada. No entanto, uma referência de recurso dinâmico só é carregada quando é usada.

  • Você está criando um estilo em que os valores 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 reparentados na árvore lógica durante o tempo de vida do aplicativo. Alterar o elemento pai também altera potencialmente o escopo de busca de recursos, portanto, se o utilizador quiser que o recurso para um elemento ressituado seja reavaliado com base no novo escopo, deve sempre usar uma referência de recurso dinâmica.

Comportamento dinâmico de pesquisa de recursos

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 procura percorre a árvore lógica até ao elemento pai e ao 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 temáticos é verificado para o tema atualmente ativo. Se o tema mudar no tempo de execução, o valor será reavaliado.

  5. Os recursos do sistema são verificados.

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

  • Se um recurso tiver sido solicitado por uma FindResource chamada e não for encontrado, uma exceção é 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 geral. 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 valor define resultados, mas o valor efetivo ainda pode vir de outros participantes no sistema de propriedades e 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 notáveis. Pelo menos uma das seguintes condições deve ser verdadeira:

Como a propriedade que está a ser definida deve ser uma propriedade DependencyProperty ou Freezable, a maioria das alterações de propriedade pode propagar-se para a interface do utilizador porque uma mudança de propriedade (o valor de recurso dinâmico alterado) é reconhecida pelo sistema de propriedades. A maioria dos controlos inclui lógica que forçará um novo layout de um controlo se a propriedade DependencyProperty mudar e essa alteração puder afetar o layout. No entanto, nem todas as propriedades que têm uma extensão de marcação DynamicResource como seu valor têm a garantia de fornecer atualizações em tempo real na interface do usuário. Essa funcionalidade ainda pode variar dependendo da propriedade e 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 ResourceDictionary devem ter uma chave, isso não significa que todos os recursos devem ter um explícito x:Key. Vários tipos de objeto suportam uma chave implícita quando definida como um recurso, onde o valor da chave está vinculado ao valor de outra propriedade. Esse tipo de chave é conhecido como chave implícita e um x:Key atributo é uma chave explícita. Você pode substituir qualquer chave implícita especificando uma chave explícita.

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

Os estilos para controles podem ser criados e 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. Do ponto de vista da solicitação, 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. Como tal, se estiver a criar temas para controlos personalizados ou a criar estilos que interajam com estilos de tema existentes, não é necessário especificar uma Diretiva x:Key para esse Style. E se você quiser usar os estilos temáticos, não precisa especificar nenhum estilo. Por exemplo, a seguinte definição de estilo 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, pode-se especificar um TargetType diretamente como o nome do tipo (ou, opcionalmente, usar {x:Type...} para retornar um Type).

Através dos mecanismos de estilo de tema padrão usados pelo WPF, esse estilo é aplicado como o estilo em tempo de execução de um Button na página, mesmo que o Button não tente ele próprio especificar sua propriedade Style ou uma referência de recurso específica para o estilo. O estilo definido na sua página aparece antes na sequência de pesquisa do que o estilo do dicionário de temas, usando a mesma chave que o estilo do dicionário de temas. 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, ainda pode especificar explicitamente o estilo com o mesmo valor de tipo que TargetType, para que fique claro na sua marcação, mas isso é opcional.

As teclas implícitas para estilos não se aplicam a um controle quando OverridesDefaultStyle é 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 criar 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 de modelos de dados.

Ver também