Extensões de marcação e WPF XAML
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 subjacente a elas. As extensões de marcação são um recurso geral da linguagem XAML e da implementação .NET de serviços XAML. Este tópico detalha especificamente as extensões de marcação para uso em WPF XAML.
Processadores XAML e extensões de marcação
De um modo geral, um analisador XAML pode interpretar um valor de atributo como uma cadeia de caracteres literal que pode ser convertida em primitiva ou convertê-la em um objeto por algum meio. Um desses meios é referenciar um conversor de tipo; isso está documentado no tópico TypeConverters e XAML. No entanto, há cenários em que um comportamento diferente é necessário. Por exemplo, um processador XAML pode ser instruído que um valor de um atributo não deve resultar em um novo objeto no gráfico de objetos. Em vez disso, o atributo deve resultar em um gráfico de objeto que faz referência a um objeto já construído em outra parte do gráfico 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. Estes são os tipos de cenários em que uma extensão de marcação pode fornecer a solução.
Sintaxe básica de extensões de marcação
Uma extensão de marcação pode ser implementada para fornecer valores para propriedades na utilização de um atributo, propriedades na utilização de um elemento de propriedade, ou 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 é então identificado pelo token de cadeia de caracteres imediatamente após a chave de abertura.
Quando usada na sintaxe de elemento de propriedade, uma extensão de marcação é visualmente igual a qualquer outro elemento que forneça um valor de propriedade: uma declaração de elemento XAML que referencia a classe de extensão de marcação como elemento, delimitado por parênteses angulares (<>).
XAML-Defined Extensões de marcação
Existem várias extensões de marcação que não são específicas para a implementação WPF de XAML, mas são, em vez disso, implementações de intrínsecas ou recursos de XAML como uma linguagem. Essas extensões de marcação são implementadas no assembly System.Xaml como parte dos serviços gerais 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 são normalmente 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 serem suportadas em leitores XAML e gravadores XAML, inclusive em 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 x:Type Markup Extension.x:Static
produz valores estáticos. Os valores vêm de entidades de código de tipo valor que não são diretamente o tipo de valor de uma propriedade de destino, mas podem ser avaliados para esse tipo. Para obter detalhes, consulte x:Static Markup Extension.x:Null
especificanull
como um valor para uma propriedade e pode ser usado para atributos ou valores de elementos de propriedade. Para mais detalhes, consulte x:Null Markup Extension.x:Array
fornece suporte para a criação de matrizes gerais em sintaxe XAML, para casos em que o suporte de coleção fornecido por elementos base do WPF e modelos de controle não é usado deliberadamente. Para obter detalhes, consulte x:Array Markup Extension.
Observação
O prefixo x:
é usado para o mapeamento de namespace XAML típico das intrínsecas da linguagem XAML, no elemento raiz de um arquivo XAML ou produção. 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 esta 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 WPF ou outros namespaces XAML não relacionados a uma estrutura específica.
WPF-Specific Extensões de marcação
As extensões de marcação mais comuns usadas na programação WPF são aquelas que suportam referências de recursos (StaticResource
e DynamicResource
) e aquelas que suportam vinculação de dados (Binding
).
StaticResource
fornece um valor para uma propriedade substituindo o valor de um recurso já definido. Uma avaliaçãoStaticResource
é feita, em última análise, no tempo de carregamento do XAML e não tem acesso ao grafo de objetos em tempo de execução. Para obter detalhes, consulte StaticResource Markup Extension.DynamicResource
fornece um valor para uma propriedade adiando esse valor para ser uma referência de tempo de execução para um recurso. Uma referência de recurso dinâmico força uma nova pesquisa cada vez que esse recurso é acessado e tem acesso ao gráfico de objeto em tempo de execução. Para obter esse acesso, o conceitoDynamicResource
é suportado por propriedades de dependência no sistema de propriedades WPF e por expressões avaliadas. Portanto, você só pode usarDynamicResource
para um destino de propriedade de dependência. Para obter detalhes, consulte DynamicResource Markup Extension.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, porque permite uma sintaxe embutida substancial para especificar uma associação de dados. Para mais detalhes, veja Binding Markup Extension.RelativeSource
fornece informações de origem para um Binding que pode navegar por vários relacionamentos possíveis na árvore de objetos em tempo de execução. Isso fornece fonte especializada para associações que são criadas em modelos multiuso ou criadas em código sem conhecimento completo da árvore de objetos ao redor. Para obter detalhes, consulte RelativeSource MarkupExtension.TemplateBinding
permite que um modelo de controlo use valores para propriedades definidas pelo modelo de objeto que serão utilizadas pela classe que vai empregar o modelo de controlo. 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 TemplateBinding Markup Extension. Para obter mais informações sobre o uso prático doTemplateBinding
, consulte Styling with ControlTemplates Sample.ColorConvertedBitmap
suporta um cenário de imagem relativamente avançado. Para obter detalhes, consulte ColorConvertedBitmap Markup Extension.ComponentResourceKey
eThemeDictionary
suportam aspetos de pesquisa de recursos, particularmente para recursos e temas que são empacotados com controles personalizados. Para obter mais informações, consulte ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension, ou Control Authoring Overview.
Cursos 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
que deriva de MarkupExtensione fornece uma implementação do método ProvideValue. Este método de cada extensão fornece o objeto que será retornado quando a extensão de marcação for avaliada. O objeto retornado é tipicamente avaliado com base nos vários segmentos de texto que são passados para a extensão de markup.
Por exemplo, a classe StaticResourceExtension fornece a implementação de superfície da pesquisa de recursos reais para que sua implementação de ProvideValue retorne o objeto solicitado, com a entrada dessa implementação específica sendo uma cadeia de caracteres usada para procurar o recurso por seu x:Key
. Muitos desses detalhes de implementação não são importantes se você estiver usando uma extensão de marcação existente.
Algumas extensões de marcação não usam argumentos de token de texto. Isso ocorre porque eles retornam um valor estático ou consistente, ou porque o contexto para o valor que 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 para que um processador XAML identifique essa classe como suporte para uma extensão de marcação. Contanto que sua base de código inclua System.Xaml e use implementações de 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. WPF define classes que permitem extensões de marcação que não seguem o padrão de nomenclatura *Extension
, por exemplo Binding. Normalmente, a razão para isso é que a classe suporta cenários além do suporte de extensão de marcação pura. No caso de Binding, essa classe oferece 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 string que seguem o nome da extensão de marcação e ainda estão 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 individuais separados não contiverem nenhum sinal de igual, cada token será tratado como um argumento do construtor. Cada parâmetro do construtor deve ser dado como o tipo esperado por essa assinatura e na ordem adequada esperada por essa assinatura.
Observação
Um processador XAML deve chamar o construtor cuja quantidade de pares corresponda ao número de argumentos. 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 como um processador XAML se comporta se existir mais de um caminho de construtor de extensão de marcação com a mesma contagem de parâmetros não está definido, mas você deve antecipar que um processador XAML tem permissão para lançar uma exceção no uso se essa situação existir nas definições de tipo de extensão de marcação.
Se os tokens separados individuais contiverem sinais de igual, 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 de propriedade em uma extensão de marcação, não importa qual comportamento você usa. É mais comum usar a propriedade
=
valor pares para extensões de marcação que têm mais de uma propriedade configurável, mesmo porque isso torna sua marcação mais intencional e você tem menos probabilidade de transpor acidentalmente 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 podem ser configuradas através da extensão na forma de propriedade=
valor, mas Binding suporta apenas dois construtores: um construtor sem parâmetros e um que define 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
A manipulação de atributos num processador XAML utiliza as chaves como indicadores de uma sequência de extensão de marcação. Também é possível produzir um valor literal de atributo de caractere de chave curva, se necessário, inserindo uma sequência de escape usando um par de chaves vazias seguido pela chave curva literal. Consulte {} Sequência de fuga - Extensão de marcação.
Aninhamento de Extensões de Marcação na Utilização de XAML
O encadeamento de várias extensões de marcação é suportado, e cada extensão de marcação será avaliada começando pela mais profunda. 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 argumento para DynamicResource
.
Extensões de marcação e sintaxe de elemento de propriedade
Quando usado como um elemento de objeto que preenche um valor de elemento de propriedade, uma classe de extensão de marcação é visualmente indistinguível de um elemento de objeto típico suportado 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 quaisquer possíveis erros de tipos nos valores das propriedades para a extensão de marcação serão diferentes, de maneira semelhante a como se trata uma propriedade de ligação tardia em outros modelos de programação. Um elemento de objeto comum será avaliado quanto à correspondência de tipos com a propriedade de destino que está a definir durante a análise do XAML.
A maioria das extensões de marcação, quando usadas na sintaxe de elemento de objeto para preencher um elemento de propriedade, não teriam conteúdo nem qualquer outra sintaxe de elemento de propriedade internamente. Assim, fecharia a etiqueta do elemento object e não forneceria nenhum elemento filho. Sempre que qualquer elemento de objeto é encontrado por um processador XAML, o construtor dessa classe é chamado, o que instancia o 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 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. Em caso afirmativo, esse valor de propriedade normalmente é dado como um atributo de propriedade no elemento object. No Namespace XAML (x:) Language Features e WPF XAML Extensions páginas de referência, as extensões de marcação que têm propriedades necessárias (e os nomes das propriedades necessárias) serão anotadas. As páginas de referência também observarão se a sintaxe do elemento objeto ou a sintaxe do atributo não é permitida para extensões de marcação específicas. Um caso notável é x:Array Markup Extension, que não pode suportar sintaxe de atributo porque o conteúdo dessa matriz deve ser especificado dentro da 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, x:Array Markup Extension requer um parâmetro type
.
Ver também
.NET Desktop feedback