Compartilhar via


Extensões de marcação e XAML do WPF

Este tópico apresenta o conceito de extensões de marcação para XAML, incluindo suas regras de sintaxe, finalidade e o modelo de objeto de classe que as sustenta. As extensões de marcação são um recurso geral da linguagem XAML e da implementação .NET dos serviços XAML. Este tópico detalha especificamente as extensões de marcação para uso no WPF XAML.

Processadores XAML e extensões de marcação

De modo geral, um analisador XAML pode interpretar um valor de atributo como uma cadeia de caracteres literal que pode ser convertida em um primitivo ou convertê-lo em um objeto por alguns meios. Um desses meios é referenciando um conversor de tipo; isso está documentado no tópico TypeConverters eXAML. No entanto, há cenários em que diferentes comportamentos são necessários. Por exemplo, um processador XAML pode ser instruído de que um valor de um atributo não deve resultar em um novo objeto no grafo de objeto. Em vez disso, o atributo deve resultar em um grafo de objeto que faz referência a um objeto já construído em outra parte do grafo ou a um objeto estático. Outro cenário é que um processador XAML pode ser instruído a usar uma sintaxe que fornece argumentos não padrão para o construtor de um objeto. Esses são os tipos de cenários em que uma extensão de marcação pode fornecer a solução.

Sintaxe de extensão de marcação básica

Uma extensão de marcação pode ser implementada para fornecer valores para propriedades em um uso de atributo, em um uso de elemento de propriedade ou em ambos.

Quando usada para fornecer um valor de atributo, a sintaxe que distingue uma sequência de extensão de marcação para um processador XAML é a presença das chaves de abertura e fechamento ({ e }). O tipo de extensão de marcação é identificado pelo token de cadeia de caracteres imediatamente após a chave de abertura.

Quando usada na sintaxe do elemento de propriedade, uma extensão de marcação é visualmente a mesma que qualquer outro elemento usado para fornecer um valor de elemento de propriedade: uma declaração de elemento XAML que faz referência à classe de extensão de marcação como um elemento, entre colchetes angulares (<>).

Extensões de marcação XAML-Defined

Existem várias extensões de marcação que não são específicas para a implementação do WPF de XAML, mas, em vez disso, são implementações de intrínsecos ou recursos de XAML como um idioma. Essas extensões de marcação são implementadas no assembly System.Xaml como parte dos serviços gerais de XAML do .NET Framework e estão dentro do namespace XAML da linguagem XAML. Em termos de uso comum de marcação, essas extensões de marcação normalmente são identificáveis pelo prefixo x:. A classe base MarkupExtension (também definida em System.Xaml) fornece o padrão que todas as extensões de marcação devem usar para ter suporte em leitores XAML e gravadores XAML, inclusive no WPF XAML.

  • x:Type fornece o objeto Type para o tipo nomeado. Este recurso é usado com mais frequência em estilos e modelos. Para obter detalhes, consulte extensão de marcação x:Type.

  • x:Static produz valores estáticos. Os valores vêm de entidades de código do tipo valor que não são diretamente o tipo do valor de uma propriedade de destino, mas podem ser avaliados como esse tipo. Para obter detalhes, consulte extensão de marcação x:Static.

  • x:Null especifica null como um valor para uma propriedade e pode ser usado para atributos ou valores de elemento de propriedade. Para obter detalhes, consulte Extensão de Marcação x:Null.

  • x:Array fornece suporte para a criação de matrizes gerais na sintaxe XAML, para casos em que o suporte à coleção fornecido por elementos base do WPF e modelos de controle não é usado deliberadamente. Para obter detalhes, consulte a Extensão de Marcação x:Array .

Nota

O prefixo x: é usado para o mapeamento típico do namespace XAML dos elementos intrínsecos da linguagem XAML, no elemento raiz de um arquivo ou em uma produção de XAML. Por exemplo, os modelos do Visual Studio para aplicativos WPF iniciam um arquivo XAML usando esse mapeamento de x:. Você pode escolher um token de prefixo diferente em seu próprio mapeamento de namespace XAML, mas essa documentação assumirá o mapeamento de x: padrão como um meio de identificar as entidades que são uma parte definida do namespace XAML para a linguagem XAML, em oposição ao namespace padrão do WPF ou a outros namespaces XAML não relacionados a uma estrutura específica.

Extensões de marcação WPF-Specific

As extensões de marcação mais comuns usadas na programação do WPF são aquelas que dão suporte a referências de recursos (StaticResource e DynamicResource) e aquelas que dão suporte à associação de dados (Binding).

  • StaticResource fornece um valor para uma propriedade substituindo o valor de um recurso já definido. Uma avaliação StaticResource é realizada durante o carregamento do XAML e não tem acesso à estrutura de objetos em tempo de execução. Para obter detalhes, consulte a extensão de marcação StaticResource .

  • DynamicResource fornece um valor para uma propriedade, adiando esse valor para ser uma referência em tempo de execução para um recurso. Uma referência dinâmica de recurso força uma nova pesquisa sempre que esse recurso é acessado e tem acesso ao grafo de objeto em tempo de execução. Para obter esse acesso, o conceito DynamicResource é suportado por propriedades de dependência no sistema de propriedades do WPF e por expressões avaliadas. Portanto, você só pode usar DynamicResource para um destino de propriedade dependente. Para obter detalhes, consulte Extensão de Marcação DynamicResource.

  • Binding fornece um valor associado a dados para uma propriedade, usando o contexto de dados que se aplica ao objeto pai em tempo de execução. Essa extensão de marcação é relativamente complexa, pois permite uma sintaxe embutida substancial para especificar uma associação de dados. Para obter detalhes, consulte Extensão de Marcação de Vinculação.

  • RelativeSource fornece informações de origem para um Binding que pode navegar por várias relações possíveis na árvore de objetos em tempo de execução. Isso fornece fornecimento especializado para associações que são criadas em modelos de vários usos ou criadas em código sem conhecimento total da árvore de objetos ao redor. Para obter detalhes, consulte RelativeSource MarkupExtension.

  • TemplateBinding permite que um modelo de controle use valores para propriedades modeladas provenientes de propriedades definidas pelo modelo de objeto da classe que usarão o modelo. Em outras palavras, a propriedade dentro da definição de modelo pode acessar um contexto que só existe quando o modelo é aplicado. Para obter detalhes, consulte a Extensão de Marcação TemplateBinding . Para obter mais informações sobre o uso prático de TemplateBinding, consulte Estilo comde exemplo ControlTemplates.

  • ColorConvertedBitmap dá suporte a um cenário de imagem relativamente avançado. Para obter detalhes, consulte a Extensão de Marcação de ColorConvertedBitmap .

  • ComponentResourceKey e ThemeDictionary dão suporte a aspectos da pesquisa de recursos, especialmente para recursos e temas que são empacotados com controles personalizados. Para obter mais informações, consulte a Extensão de Marcação ComponentResourceKey , a Extensão de Marcação ThemeDictionary , ou a Visão Geral de Criação de Controle .

*Classes de extensão

Para a linguagem XAML geral e as extensões de marcação específicas do WPF, o comportamento de cada extensão de marcação é identificado para um processador XAML por meio de uma classe *Extension derivada de MarkupExtensione fornece uma implementação do método ProvideValue. Esse método em cada extensão fornece o objeto retornado quando a extensão de marcação é avaliada. O objeto retornado normalmente é avaliado com base nos vários tokens de string que são passados para a extensão de marcação.

Por exemplo, a classe StaticResourceExtension fornece a implementação superficial da pesquisa real de recursos, de modo que sua implementação ProvideValue retorne o objeto solicitado, com a entrada dessa implementação específica sendo uma string usada para pesquisar o recurso por seu x:Key. Grande parte desse detalhe de implementação não é importante se você estiver usando uma extensão de marcação existente.

Algumas extensões de marcação não usam argumentos de token de cadeia de caracteres. Isso ocorre porque eles retornam um valor estático ou consistente ou porque o contexto para qual valor deve ser retornado está disponível por meio de um dos serviços passados pelo parâmetro serviceProvider.

O padrão de nomenclatura *Extension é para conveniência e consistência. Não é necessário que um processador XAML identifique essa classe como suporte para uma extensão de marcação. Desde que sua base de código inclua System.Xaml e use implementações dos Serviços XAML do .NET Framework, tudo o que é necessário para ser reconhecido como uma extensão de marcação XAML é derivar de MarkupExtension e dar suporte a uma sintaxe de construção. O WPF define classes de habilitação de extensão de marcação que não seguem o padrão de nomenclatura *Extension, por exemplo, Binding. Normalmente, o motivo para isso é que a classe dá suporte a cenários além do suporte à extensão de marcação pura. No caso de Binding, essa classe dá suporte ao acesso em tempo de execução a métodos e propriedades do objeto para cenários que não têm nada a ver com XAML.

Interpretação do texto de inicialização da classe de extensão

Os tokens de sequência de caracteres que seguem o nome da extensão de marcação e permanecem dentro das chaves são interpretados por um processador XAML de uma das seguintes maneiras:

  • Uma vírgula sempre representa o separador ou delimitador de tokens individuais.

  • Se os tokens separados individuais não contiverem sinais iguais, cada token será tratado como um argumento de construtor. Cada parâmetro de construtor deve ser fornecido como o tipo esperado por essa assinatura e na ordem adequada esperada por essa assinatura.

    Nota

    Um processador XAML deve chamar o construtor que corresponda à quantidade de argumentos para o número apropriado de pares. Por esse motivo, se você estiver implementando uma extensão de marcação personalizada, não forneça vários construtores com a mesma contagem de argumentos. O comportamento de o que um processador XAML faz se mais de um caminho de construtor de extensão de marcação com a mesma contagem de parâmetros existir não está definido, mas você deve prever que um processador XAML está autorizado a lançar uma exceção durante o uso se essa situação existir nas definições de tipo da extensão de marcação.

  • Se os tokens separados individuais contiverem sinais iguais, um processador XAML primeiro chamará o construtor sem parâmetros para a extensão de marcação. Em seguida, cada par name=value é interpretado como um nome de propriedade que existe na extensão de marcação e um valor a ser atribuído a essa propriedade.

  • Se houver um resultado paralelo entre o comportamento do construtor e o comportamento de configuração da propriedade em uma extensão de marcação, não importa qual comportamento você usa. É mais comum usar a propriedade =pares de valor para extensões de marcação que têm mais de uma propriedade configurável, pelo menos porque isso torna sua marcação mais intencional e você tem menos chances de transpor acidentalmente os parâmetros do construtor. (Quando você especifica pares property=value, essas propriedades podem estar em qualquer ordem.) Além disso, não há garantia de que uma extensão de marcação forneça um parâmetro de construtor que define cada uma de suas propriedades configuráveis. Por exemplo, Binding é uma extensão de marcação, com muitas propriedades que são configuráveis por meio da extensão na forma de propriedade =valor, mas Binding só suporta dois construtores: um construtor sem parâmetros e um que estabelece um caminho inicial.

  • Uma vírgula literal não pode ser passada para uma extensão de marcação sem escape.

Sequências de escape e extensões de marcação

O tratamento de atributos em um processador XAML usa as chaves como indicadores de uma sequência de extensão de marcação. Também é possível produzir um valor de atributo representado por um caractere de chave literal, se necessário, inserindo uma sequência de escape usando um par de chaves vazias seguido pela chave literal. Consulte a sequência de escape {} - extensão de marcação.

Aninhamento de Extensões de Marcação no Uso de XAML

Há suporte para aninhamento de várias extensões de marcação e cada extensão de marcação será avaliada mais profundamente primeiro. Por exemplo, considere o seguinte uso:

<Setter Property="Background"  
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />  

Nesse uso, a instrução x:Static é avaliada primeiro e retorna uma cadeia de caracteres. Essa cadeia de caracteres é então usada como o argumento para DynamicResource.

Sintaxe de Extensões de Marcação e Sintaxe de Elementos de Propriedade

Quando usada como um elemento de objeto que preenche o valor de um elemento de propriedade, uma classe de extensão de marcação é visualmente indistinguível de um elemento de objeto típico respaldado por tipo que pode ser usado em XAML. A diferença prática entre um elemento de objeto típico e uma extensão de marcação é que a extensão de marcação é avaliada como um valor tipado ou adiada como uma expressão. Portanto, os mecanismos para possíveis erros de tipo de valores de propriedade para a extensão de marcação serão diferentes, semelhante à forma como uma propriedade com limite tardio é tratada em outros modelos de programação. Um elemento de objeto padrão será avaliado para compatibilidade de tipo com a propriedade de destino que está sendo configurada quando o XAML é analisado.

A maioria das extensões de marcação, quando usadas na sintaxe do elemento de objeto para preencher um elemento de propriedade, não teria conteúdo nem qualquer sintaxe de elemento de propriedade adicional dentro. Portanto, você fecha a tag de elemento de objeto e não fornece elementos filhos. Sempre que qualquer elemento de objeto é encontrado por um processador XAML, o construtor dessa classe é chamado, o que cria uma instância do objeto criado a partir do elemento analisado. Uma classe de extensão de marcação não é diferente: se você quiser que sua extensão de marcação seja utilizável na sintaxe do elemento de objeto, você deve fornecer um construtor sem parâmetros. Algumas extensões de marcação existentes têm pelo menos um valor de propriedade necessário que deve ser especificado para inicialização efetiva. Nesse caso, esse valor de propriedade normalmente é fornecido como um atributo de propriedade no elemento de objeto. No namespace XAML (x:) Recursos de linguagem e páginas de referência de Extensões XAML do WPF, serão observadas extensões de marcação que tenham propriedades necessárias (e os nomes das propriedades necessárias). As páginas de referência também indicarão se a sintaxe de elemento de objeto ou a sintaxe de atributo não são permitidas para extensões de marcação específicas. Um caso notável é a Extensão de Marcação x:Array, que não pode dar suporte à sintaxe de atributo porque o conteúdo desse array deve ser especificado na marcação como conteúdo. O conteúdo da matriz é tratado como objetos gerais, portanto, nenhum conversor de tipo padrão para o atributo é viável. Além disso, a Extensão de Marcação x:Array requer um parâmetro type.

Consulte também