Partilhar via


Sintaxe XAML em detalhes

Este tópico define os termos usados para descrever os elementos da sintaxe XAML. Esses termos são usados com frequência ao longo do restante desta documentação, tanto para a documentação do WPF especificamente quanto para as outras estruturas que usam XAML ou os conceitos XAML básicos habilitados pelo suporte à linguagem XAML no nível system.Xaml. Este tópico expande a terminologia básica introduzida no tópico XAML no WPF.

A especificação da linguagem XAML

A terminologia da sintaxe XAML definida aqui também é definida ou referenciada dentro da especificação da linguagem XAML. XAML é uma linguagem baseada em XML e segue ou expande as regras estruturais XML. Parte da terminologia é compartilhada ou se baseia na terminologia comumente usada ao descrever a linguagem XML ou o modelo de objeto de documento XML.

Para obter mais informações sobre a especificação da linguagem XAML, baixe [MS-XAML] do Centro de Download da Microsoft.

XAML e CLR

XAML é uma linguagem de marcação. O CLR (Common Language Runtime), conforme implícito pelo nome, habilita a execução de runtime. O XAML não é, por si só, um dos idiomas comuns consumidos diretamente pelo runtime clr. Em vez disso, você pode pensar em XAML como tendo seu próprio sistema de tipos. O sistema de análise XAML específico usado pelo WPF é baseado no CLR e no sistema de tipos CLR. Os tipos XAML são mapeados para tipos CLR para criar uma representação de tempo de execução quando o XAML para WPF é processado. Por esse motivo, o restante da discussão da sintaxe neste documento incluirá referências ao sistema de tipos CLR, embora as discussões de sintaxe equivalentes na especificação da linguagem XAML não o façam. (De acordo com o nível de especificação da linguagem XAML, os tipos XAML podem ser mapeados para qualquer outro sistema de tipo, que não precisa ser o CLR, mas isso exigiria a criação e o uso de um analisador XAML diferente.)

Membros de Tipos e Herança de Classes

Propriedades e eventos que surgem como membros XAML de um tipo WPF geralmente são neste caso herdados de tipos base. Por exemplo, considere este exemplo: <Button Background="Blue" .../>. A propriedade Background não é uma propriedade diretamente declarada na classe Button, ao examinar a definição da classe, os resultados da reflexão ou a documentação. Em vez disso, Background é herdado da classe base Control.

O comportamento de herança de classe de elementos XAML do WPF é uma diferença significativa em relação a uma interpretação imposta por esquema da marcação XML. A herança de classe pode se tornar complexa, especialmente quando classes base intermediárias são abstratas ou quando as interfaces estão envolvidas. Esse é um dos motivos pelos quais o conjunto de elementos XAML e seus atributos permitidos é difícil de representar com precisão e completamente usando os tipos de esquema que normalmente são usados para programação XML, como formato DTD ou XSD. Outro motivo é que a extensibilidade e os recursos de mapeamento de tipo da própria linguagem XAML impedem a integridade de qualquer representação fixa dos tipos e membros permitidos.

Sintaxe do elemento objeto

A sintaxe do elemento Object é a sintaxe de marcação XAML que instância uma classe ou estrutura CLR por meio da declaração de um elemento XML. Essa sintaxe se assemelha à sintaxe do elemento de outras linguagens de marcação, como HTML. A sintaxe do elemento objeto começa com um colchete de ângulo esquerdo (<), seguido imediatamente pelo nome do tipo da classe ou estrutura que está sendo instanciada. Zero ou mais espaços podem seguir o nome do tipo, e zero ou mais atributos também podem ser declarados no elemento objeto, com um ou mais espaços separando cada par "nome"="valor". Por fim, um dos seguintes deve ser verdadeiro:

  • O elemento e a marca devem ser fechados por uma barra (/) seguida imediatamente por um colchete de ângulo reto (>).

  • A marca de abertura deve ser concluída por um colchete de ângulo reto (>). Outros elementos de objeto, elementos de propriedade ou texto interno podem seguir a marca de abertura. O conteúdo que pode estar contido aqui normalmente é restringido pelo modelo de objeto do elemento. A tag de fechamento equivalente para o elemento de objeto também deve existir, em aninhamento e equilíbrio adequados com outros pares de tags de abertura e fechamento.

O XAML, conforme implementado pelo .NET, tem um conjunto de regras que mapeiam elementos de objeto em tipos, atributos em propriedades ou eventos e namespaces XAML para namespaces CLR e assembly. Para WPF e .NET, os elementos de objeto XAML são mapeados para tipos .NET, conforme definido em assemblies referenciados, enquanto os atributos são mapeados para os membros desses tipos. Quando você faz referência a um tipo CLR no XAML, você também tem acesso aos membros herdados desse tipo.

Por exemplo, o exemplo a seguir é a sintaxe do elemento de objeto que cria uma instância nova da classe Button e também especifica um atributo Name e um valor para esse atributo:

<Button Name="CheckoutButton"/>

O exemplo a seguir é a sintaxe do elemento de objeto que também inclui a sintaxe da propriedade de conteúdo XAML. O texto interno contido dentro será usado para definir a propriedade de conteúdo XAML TextBox, Text.

<TextBox>This is a Text Box</TextBox>

Modelos de conteúdo

Uma classe pode dar suporte a um uso como um elemento de objeto XAML em termos de sintaxe, mas esse elemento só funcionará corretamente em um aplicativo ou página quando ele for colocado em uma posição esperada de um modelo de conteúdo geral ou árvore de elementos. Por exemplo, um MenuItem normalmente deve ser colocado apenas como filho de uma classe derivada MenuBase, como Menu. Modelos de conteúdo para elementos específicos são documentados como parte das observações nas páginas de classe para controles e outras classes do WPF que podem ser usadas como elementos XAML.

Propriedades de elementos de objeto

As propriedades em XAML são definidas por uma variedade de sintaxes possíveis. Qual sintaxe pode ser usada para uma propriedade específica variará, com base nas características do sistema de tipos subjacentes da propriedade que você está definindo.

Ao definir valores de propriedades, você adiciona recursos ou características a objetos conforme eles existem no grafo de objeto de tempo de execução. O estado inicial do objeto criado de um elemento de objeto baseia-se no comportamento do construtor sem parâmetros. Normalmente, seu aplicativo usará algo diferente de uma instância completamente padrão de qualquer objeto determinado.

Sintaxe de atributo (Propriedades)

A sintaxe do atributo é a sintaxe de marcação XAML que define um valor para uma propriedade declarando um atributo em um elemento de objeto existente. O nome do atributo deve corresponder ao nome do membro CLR da propriedade da classe que apoia o elemento de objeto relevante. O nome do atributo é seguido por um operador de atribuição (=). O valor do atributo deve ser uma cadeia de caracteres entre aspas.

Nota

Você pode usar aspas alternadas para colocar uma aspa literal dentro de um atributo. Por exemplo, você pode usar aspas simples como um meio para declarar uma cadeia de caracteres que contém um caractere de aspas dupla dentro dela. Se você usar aspas simples ou duplas, deverá usar um par correspondente para abrir e fechar a sequência de valor de atributo. Também há sequências de escape ou outras técnicas disponíveis para contornar restrições de caractere impostas por qualquer sintaxe XAML específica. Consulte entidades de caractere XML edo XAML.

Para ser definida por meio da sintaxe de atributo, uma propriedade deve ser pública e deve ser gravável. O valor da propriedade no sistema de tipos subjacente deve ser um tipo de valor, ou deve ser um tipo de referência que possa ser instanciado ou referenciado por um processador XAML ao acessar o tipo subjacente relevante.

Para eventos XAML do WPF, o evento referenciado como o nome do atributo deve ser público e ter um representante público.

A propriedade ou evento deve ser um membro da classe ou estrutura instanciada pelo elemento de objeto que contém.

Processamento de valores de atributo

O valor da cadeia de caracteres contido nas aspas de abertura e fechamento é processado por um processador XAML. Para propriedades, o comportamento de processamento padrão é determinado pelo tipo da propriedade CLR subjacente.

O valor do atributo é preenchido por um dos seguintes, usando esta ordem de processamento:

  1. Se o processador XAML encontrar uma chave ou um elemento de objeto que deriva de MarkupExtension, a extensão de marcação referenciada será avaliada primeiro em vez de processar o valor como uma cadeia de caracteres e o objeto retornado pela extensão de marcação será usado como o valor. Em muitos casos, o objeto retornado por uma extensão de marcação será uma referência a um objeto existente ou uma expressão que adia a avaliação até o tempo de execução e não é um objeto recém-instanciado.

  2. Se a propriedade for declarada com um TypeConverteratribuído ou o tipo de valor dessa propriedade for declarado com um TypeConverteratribuído, o valor da cadeia de caracteres do atributo será enviado para o conversor de tipo como uma entrada de conversão e o conversor retornará uma nova instância de objeto.

  3. Se não houver TypeConverter, uma conversão direta para o tipo de propriedade será tentada. Esse nível final é uma conversão direta no valor nativo do analisador entre tipos primitivos da linguagem XAML ou uma verificação dos nomes das constantes nomeadas em uma enumeração (o analisador acessa os valores correspondentes).

Valores de atributo de enumeração

As enumerações em XAML são processadas intrinsecamente por analisadores XAML e os membros de uma enumeração devem ser especificados especificando o nome da cadeia de caracteres de uma das constantes nomeadas da enumeração.

Para valores de enumeração nonflag, o comportamento nativo é processar a cadeia de caracteres de um valor de atributo e resolvê-la para um dos valores de enumeração. Você não especifica a enumeração no formato enumeração.Value, como você faz no código. Em vez disso, você especifica apenas Valor, e Enumeração é inferido com base no tipo de propriedade que você está configurando. Se você especificar um atributo na forma Enumeração.Valor, ele não será resolvido corretamente.

Para enumerações flagwise, o comportamento é baseado no método Enum.Parse. Você pode especificar vários valores para uma enumeração flagwise separando cada valor com uma vírgula. No entanto, você não pode combinar valores de enumeração que não são sinalizadores. Por exemplo, você não pode usar a sintaxe de vírgula para tentar criar uma Trigger que atua sobre múltiplas condições de uma enumeração não-flag:

<!--This will not compile, because Visibility is not a flagwise enumeration.-->  
...  
<Trigger Property="Visibility" Value="Collapsed,Hidden">  
  <Setter ... />  
</Trigger>  
...  

Enumerações sinalizadoras que dão suporte a atributos que são configuráveis em XAML são raras no WPF. No entanto, uma dessas enumerações é StyleSimulations. Você pode, por exemplo, usar a sintaxe de atributo flagwise delimitada por vírgulas para modificar o exemplo fornecido nas Observações da classe Glyphs; StyleSimulations = "BoldSimulation" pode se tornar StyleSimulations = "BoldSimulation,ItalicSimulation". KeyBinding.Modifiers é outra propriedade em que mais de um valor de enumeração pode ser especificado. No entanto, essa propriedade é um caso especial, pois a enumeração ModifierKeys dá suporte a seu próprio conversor de tipo. O conversor de tipo para modificadores usa um sinal de adição (+) como um delimitador em vez de uma vírgula (,). Essa conversão dá suporte à sintaxe mais tradicional para representar combinações de chaves na programação do Microsoft Windows, como "Ctrl+Alt".

Propriedades e referências de nome de membro do evento

Ao especificar um atributo, você pode referenciar qualquer propriedade ou evento que exista como um membro do tipo CLR instanciado do elemento de objeto que o contém.

Ou você pode referenciar uma propriedade anexada ou um evento anexado, independentemente do elemento de objeto que contém. (As propriedades anexadas são discutidas em uma próxima seção.)

Você também pode nomear qualquer evento de um objeto pelo qual seja acessível através do namespace padrão, usando um typeName.evento nome parcialmente qualificado; esta sintaxe permite anexar manipuladores para eventos roteados em que o manipulador visa lidar com o roteamento de eventos de elementos filhos, mesmo que o elemento pai não possua esse evento em sua tabela de membros. Essa sintaxe se assemelha a uma sintaxe de evento anexada, mas o evento aqui não é um verdadeiro evento anexado. Em vez disso, você está fazendo referência a um evento com um nome qualificado. Para obter mais informações, consulte Visão geral de eventos roteados.

Para alguns cenários, os nomes de propriedade às vezes são fornecidos como o valor de um atributo, em vez do nome do atributo. Esse nome de propriedade também pode incluir qualificadores, como a propriedade especificada na forma ownerType.dependencyPropertyName. Esse cenário é comum ao escrever estilos ou modelos em XAML. As regras de processamento para nomes de propriedade fornecidos como um valor de atributo são diferentes e são regidas pelo tipo da propriedade que está sendo definida ou pelos comportamentos de subsistemas WPF específicos. Para obter detalhes, consulte Estilo e Modelagem.

Outro uso para nomes de propriedade é quando um valor de atributo descreve uma relação propriedade-propriedade. Esse recurso é usado para associação de dados e para destinos de storyboard e é habilitado pela classe PropertyPath e seu conversor de tipos. Para obter uma descrição mais completa da semântica de pesquisa, consulte Sintaxe XAML do PropertyPath.

Sintaxe do elemento property

Sintaxe do elemento property é uma sintaxe que diverge um pouco das regras básicas de sintaxe XML para elementos. No XML, o valor de um atributo é uma cadeia de caracteres de fato, com a única variação possível sendo qual formato de codificação de cadeia de caracteres está sendo usado. No XAML, você pode atribuir outros elementos de objeto para ser o valor de uma propriedade. Essa funcionalidade é habilitada pela sintaxe do elemento de propriedade. Em vez de a propriedade ser especificada como um atributo dentro da tag do elemento, ela é especificada usando uma tag de abertura de elemento no formato elementTypeName.propertyName, onde o valor da propriedade é especificado dentro, e então o elemento da propriedade é fechado.

Especificamente, a sintaxe começa com um colchete de ângulo esquerdo (<), seguido imediatamente pelo nome do tipo da classe ou estrutura na qual a sintaxe do elemento de propriedade está contida. Isso é seguido imediatamente por um único ponto (.), em seguida, pelo nome de uma propriedade, em seguida, por um colchete de ângulo reto (>). Assim como acontece com a sintaxe do atributo, essa propriedade deve existir dentro dos membros públicos declarados do tipo especificado. O valor a ser atribuído à propriedade está contido no elemento de propriedade. Normalmente, o valor é fornecido como um ou mais elementos de objeto, pois especificar objetos como valores é o cenário que a sintaxe do elemento de propriedade destina-se a abordar. Por fim, uma marca de fechamento equivalente especificando o mesmo elementTypeName.combinação propertyName deve ser fornecida, em aninhamento e equilíbrio adequados com outras marcas de elemento.

Por exemplo, o seguinte é a sintaxe do elemento de propriedade para a propriedade ContextMenu de um Button.

<Button>
  <Button.ContextMenu>
    <ContextMenu>
      <MenuItem Header="1">First item</MenuItem>
      <MenuItem Header="2">Second item</MenuItem>
    </ContextMenu>
  </Button.ContextMenu>
  Right-click me!</Button>

O valor dentro de um elemento de propriedade também pode ser fornecido como texto interno, nos casos em que o tipo de propriedade que está sendo especificado é um tipo de valor primitivo, como String, ou uma enumeração em que um nome é especificado. Esses dois usos são um pouco incomuns, pois cada um desses casos também pode usar uma sintaxe de atributo mais simples. Um cenário para preencher um elemento de propriedade com uma cadeia de caracteres é para propriedades que não são a propriedade de conteúdo XAML, mas ainda são usadas para representação de texto de interface do usuário, e elementos específicos de espaço em branco, como feeds de linha, são necessários para aparecer nesse texto da interface do usuário. A sintaxe de atributo não pode preservar os feeds de linha, mas a sintaxe do elemento de propriedade pode, desde que a preservação significativa do espaço em branco esteja ativa (para obter detalhes, consulte Processamento de espaço em branco no XAML). Outro cenário é para que diretiva x:Uid possa ser aplicada ao elemento de propriedade e, portanto, marcar o valor dentro como um valor que deve ser localizado no BAML de saída do WPF ou por outras técnicas.

Um elemento de propriedade não é representado na árvore lógica do WPF. Um elemento de propriedade é apenas uma sintaxe específica para definir uma propriedade e não é um elemento que tem uma instância ou objeto com suporte. (Para obter detalhes sobre o conceito de árvore lógica, consulte Árvores no WPF.)

Para propriedades em que há suporte para sintaxe de elemento de propriedade e atributo, as duas sintaxes geralmente têm o mesmo resultado, embora sutilezas como o tratamento de espaço em branco possam variar ligeiramente entre sintaxes.

Sintaxe da coleção

A especificação XAML requer implementações de processador XAML para identificar propriedades em que o tipo de valor é uma coleção. A implementação geral do processador XAML no .NET baseia-se no código gerenciado e no CLR e identifica tipos de coleção por meio de um dos seguintes:

  • O tipo implementa IList.

  • O tipo implementa IDictionary.

  • O tipo deriva de Array (para obter mais informações sobre matrizes no XAML, consulte a Extensão de Marcação x:Array .)

Se o tipo de uma propriedade for uma coleção, o tipo de coleção inferido não precisará ser especificado na marcação como um elemento de objeto. Em vez disso, os elementos que se destinam a se tornar os itens da coleção são especificados como um ou mais subelementos do elemento de propriedade. Cada item desse tipo é transformado em um objeto durante o carregamento e adicionado à coleção ao invocar o método Add da coleção implícita. Por exemplo, a propriedade Triggers de Style adota o tipo especializado de coleção TriggerCollection, que implementa IList. Não é necessário instanciar um elemento de objeto TriggerCollection na marcação. Em vez disso, você especifica um ou mais itens Trigger como elementos dentro do elemento de propriedade Style.Triggers, em que Trigger (ou uma classe derivada) é o tipo esperado como o tipo de item para o TriggerCollectionfortemente tipado e implícito.

<Style x:Key="SpecialButton" TargetType="{x:Type Button}">
  <Style.Triggers>
    <Trigger Property="Button.IsMouseOver" Value="true">
      <Setter Property = "Background" Value="Red"/>
    </Trigger>
    <Trigger Property="Button.IsPressed" Value="true">
      <Setter Property = "Foreground" Value="Green"/>
    </Trigger>
  </Style.Triggers>
</Style>

Uma propriedade pode ser um tipo de coleção e a propriedade de conteúdo XAML para esse tipo e tipos derivados, que é discutida na próxima seção deste tópico.

Um elemento de coleção implícita cria um membro na representação de árvore lógica, mesmo que ele não apareça na marcação como um elemento. Normalmente, o construtor do tipo pai executa a instanciação para a coleção que é uma de suas propriedades, e a coleção inicialmente vazia torna-se parte da árvore de objetos.

Nota

A lista genérica e as interfaces de dicionário (IList<T> e IDictionary<TKey,TValue>) não têm suporte para detecção de coleção. No entanto, você pode usar a classe List<T> como uma classe base, pois ela implementa IList diretamente ou Dictionary<TKey,TValue> como uma classe base, pois ela implementa IDictionary diretamente.

Nas páginas de referência do .NET para tipos de coleção, essa sintaxe, que omite deliberadamente o elemento de objeto de uma coleção, é ocasionalmente mencionada nas seções de sintaxe XAML como Sintaxe de Coleção Implícita.

Com exceção do elemento raiz, em um arquivo XAML, cada elemento de objeto aninhado como filho de outro elemento é, na verdade, um elemento que se encaixa em um ou ambos os seguintes casos: um membro de uma propriedade de coleção implícita do elemento pai ou que especifica o valor da propriedade de conteúdo XAML para o elemento pai (as propriedades de conteúdo XAML serão abordadas em uma seção futura). Em outras palavras, a relação entre elementos pai e elementos filho em uma página de markup é na verdade um único objeto na raiz, e cada elemento abaixo da raiz é uma instância única que fornece um valor de propriedade do pai ou um dos itens dentro de uma coleção, que também é um valor de propriedade do tipo coleção do pai. Esse conceito de raiz única é comum com XML e é frequentemente reforçado no comportamento de APIs que carregam XAML, como Load.

O exemplo a seguir é uma sintaxe com o elemento de objeto de uma coleção (GradientStopCollection) especificada explicitamente.

<LinearGradientBrush>  
  <LinearGradientBrush.GradientStops>  
    <GradientStopCollection>  
      <GradientStop Offset="0.0" Color="Red" />  
      <GradientStop Offset="1.0" Color="Blue" />  
    </GradientStopCollection>  
  </LinearGradientBrush.GradientStops>  
</LinearGradientBrush>  

Observe que nem sempre é possível declarar explicitamente a coleção. Por exemplo, a tentativa de declarar TriggerCollection explicitamente no exemplo de Triggers mostrado anteriormente falharia. Declarar explicitamente a coleção requer que a classe de coleção seja compatível com um construtor sem parâmetros e TriggerCollection não tem um construtor sem parâmetros.

Propriedades de conteúdo XAML

A sintaxe de conteúdo XAML é uma sintaxe que só está habilitada em classes que especificam o ContentPropertyAttribute como parte de sua declaração de classe. O ContentPropertyAttribute faz referência ao nome da propriedade que é a propriedade de conteúdo para esse tipo de elemento (incluindo classes derivadas). Quando processado por um processador XAML, todos os elementos filho ou texto interno encontrados entre as marcas de abertura e fechamento do elemento de objeto serão atribuídos ao valor da propriedade de conteúdo XAML desse objeto. Você tem permissão para especificar elementos de propriedade explícitos para a propriedade de conteúdo, mas esse uso geralmente não é mostrado nas seções de sintaxe XAML na referência .NET. A técnica explícita/detalhada tem um valor ocasional para clareza na marcação ou como uma questão de estilo de marcação, mas geralmente a intenção de uma propriedade de conteúdo é simplificar a marcação de forma que elementos que estão relacionados de forma intuitiva como pai-filho possam ser aninhados diretamente. Tags de propriedade de elemento relativas a outras propriedades em um elemento não são atribuídas como "conteúdo" por uma definição de linguagem XAML estrita; são processadas anteriormente de acordo com a ordem de processamento do analisador XAML e não são consideradas "conteúdo".

Os valores da propriedade de conteúdo XAML devem ser contíguos

O valor de uma propriedade de conteúdo XAML deve ser fornecido inteiramente antes ou inteiramente depois de quaisquer outros elementos de propriedade nesse elemento de objeto. Isso é verdade se o valor de uma propriedade de conteúdo XAML é especificado como uma cadeia de caracteres ou como um ou mais objetos. Por exemplo, a marcação a seguir não é analisada:

<Button>I am a
  <Button.Background>Blue</Button.Background>  
  blue button</Button>  

Isso é essencialmente ilegal porque se essa sintaxe fosse explicitada usando a sintaxe do elemento de propriedade para a propriedade de conteúdo, a propriedade de conteúdo seria definida duas vezes:

<Button>  
  <Button.Content>I am a </Button.Content>  
  <Button.Background>Blue</Button.Background>  
  <Button.Content> blue button</Button.Content>  
</Button>  

Um exemplo igualmente ilegal é se a propriedade de conteúdo for uma coleção e os elementos filho estiverem misturados com elementos de propriedade.

<StackPanel>  
  <Button>This example</Button>  
  <StackPanel.Resources>  
    <SolidColorBrush x:Key="BlueBrush" Color="Blue"/>  
  </StackPanel.Resources>  
  <Button>... is illegal XAML</Button>  
</StackPanel>  

Propriedades de Conteúdo e Sintaxe de Coleção Combinadas

Para aceitar mais de um único elemento de objeto como conteúdo, o tipo da propriedade de conteúdo deve ser especificamente um tipo de coleção. Semelhante à sintaxe de elemento de propriedade para tipos de coleção, um processador XAML deve identificar tipos que são tipos de coleção. Se um elemento tiver uma propriedade de conteúdo XAML e o tipo da propriedade de conteúdo XAML for uma coleção, o tipo de coleção implícita não precisará ser especificado na marcação como um elemento de objeto e a propriedade de conteúdo XAML não precisará ser especificada como um elemento de propriedade. Portanto, o modelo de conteúdo aparente na marcação agora pode ter mais de um elemento filho atribuído como conteúdo. Veja a seguir a sintaxe de conteúdo de uma classe derivada de Panel. Todas as classes derivadas Panel estabelecem que a propriedade de conteúdo XAML seja Children, o que requer um valor do tipo UIElementCollection.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel>
    <Button>Button 1</Button>
    <Button>Button 2</Button>
    <Button>Button 3</Button>
  </StackPanel>
</Page>

Observe que nem o elemento de propriedade para Children nem o elemento para o UIElementCollection é necessário na marcação. Esse é um recurso de design de XAML para que elementos recursivamente contidos que definem uma interface do usuário sejam representados de forma mais intuitiva como uma árvore de elementos aninhados com relações de elemento pai-filho imediatas, sem intervir marcas de elementos de propriedade ou objetos de coleção. Na verdade, UIElementCollection não pode ser especificado explicitamente na marcação como um elemento de objeto, por design. Como seu único uso pretendido é como uma coleção implícita, UIElementCollection não expõe um construtor público sem parâmetros e, portanto, não pode ser instanciado como um elemento de objeto.

Combinando elementos de propriedade e elementos de objeto em um objeto com uma propriedade de conteúdo

A especificação XAML declara que um processador XAML pode impor que os elementos de objeto usados para preencher a propriedade de conteúdo XAML dentro de um elemento de objeto devem ser contíguos e não devem ser misturados. Essa restrição contra a combinação de elementos de propriedade e conteúdo é imposta pelos processadores XAML do WPF.

Você pode ter um elemento filho de objeto como a primeira marcação imediata dentro de um elemento de objeto. Em seguida, você pode introduzir elementos de propriedade. Ou você pode especificar um ou mais elementos de propriedade e, em seguida, conteúdo e mais elementos de propriedade. Mas uma vez que um elemento de propriedade segue o conteúdo, você não pode introduzir mais conteúdo, você só pode adicionar elementos de propriedade.

Esse requisito de ordem de elemento de propriedade/conteúdo não se aplica ao texto interno usado como conteúdo. No entanto, ainda é um bom estilo de marcação manter o texto interno contíguo, pois um espaço em branco significativo será difícil de detectar visualmente na marcação se os elementos de propriedade forem intercalados com texto interno.

XAML Namespaces

Nenhum dos exemplos de sintaxe anteriores especificou um namespace XAML diferente do namespace XAML padrão. Em aplicativos WPF típicos, o namespace XAML padrão é especificado para ser o namespace do WPF. Você pode especificar namespaces XAML diferentes do namespace XAML padrão e ainda usar sintaxe semelhante. Mas, em qualquer lugar em que uma classe seja nomeada que não esteja acessível dentro do namespace XAML padrão, esse nome de classe deve ser precedido com o prefixo do namespace XAML conforme mapeado para o namespace CLR correspondente. Por exemplo, <custom:Example/> é a sintaxe de elemento de objeto para criar uma instância da classe Example, onde o namespace CLR que contém essa classe (e possivelmente as informações de assembly externo que contêm tipos auxiliares) foi mapeado anteriormente para o prefixo custom.

** Para obter mais informações sobre Namespaces XAML, consulte Namespaces XAML e Mapeamento de Namespace para XAML do WPF.

Extensões de marcação

O XAML define uma entidade de programação chamada extensão de marcação que permite alterar o tratamento padrão do processador XAML de valores de atributos de cadeias de caracteres ou elementos de objeto, e adia o processamento para uma classe de suporte. O caractere que identifica uma extensão de marcação para um processador XAML ao usar a sintaxe de atributo é a chave de abertura ({), seguida por qualquer caractere que não seja uma chave de fechamento (}). A primeira cadeia de caracteres após a chave de abertura deve referenciar a classe que fornece o comportamento de extensão específico, em que a referência poderá omitir a subcadeia de caracteres "Extension" se essa subcadeia de caracteres fizer parte do nome da classe verdadeira. Depois disso, um único espaço pode aparecer e, em seguida, cada caractere subsequente é usado como entrada pela implementação da extensão, até que a chave de fechamento seja encontrada.

A implementação de XAML do .NET usa a classe abstrata MarkupExtension como base para todas as extensões de marcação compatíveis com o WPF, bem como outras estruturas ou tecnologias. As extensões de marcação que o WPF implementa especificamente geralmente se destinam a fornecer um meio de referenciar outros objetos existentes ou fazer referências adiadas a objetos que serão avaliados em tempo de execução. Por exemplo, uma vinculação de dados simples do WPF é feita especificando a extensão de marcação {Binding} no lugar do valor que uma propriedade específica normalmente assumiria. Muitas das extensões de marcação do WPF permitem uma sintaxe de atributo para propriedades em que uma sintaxe de atributo não seria possível de outra forma. Por exemplo, um objeto Style é um tipo relativamente complexo que contém uma série aninhada de objetos e propriedades. Os estilos no WPF normalmente são definidos como um recurso em um ResourceDictionarye, em seguida, referenciados por meio de uma das duas extensões de marcação do WPF que solicitam um recurso. A extensão de marcação adia a avaliação do valor de uma propriedade para uma pesquisa de recurso e permite definir o valor da propriedade Style, usando o tipo Style, na sintaxe do atributo, como no exemplo a seguir:

<Button Style="{StaticResource MyStyle}">My button</Button>

Aqui, StaticResource identifica a classe StaticResourceExtension, que fornece a implementação da extensão de marcação. A próxima cadeia de caracteres MyStyle é usada como entrada para o construtor não padrão de StaticResourceExtension, em que o parâmetro, conforme retirado da cadeia de caracteres correspondente à extensão, declara o ResourceKeysolicitado. MyStyle deve ser o valor x:Key de um Style definido como um recurso. A Extensão de Marcação StaticResource solicita que o recurso seja usado para fornecer o valor da propriedade Style através da lógica de busca de recursos estáticos durante o carregamento.

Para obter mais informações sobre extensões de marcação, consulte Extensões de Marcação e XAMLdo WPF. Para obter uma referência de extensões de marcação e outros recursos de programação XAML habilitados na implementação geral do XAML do .NET, consulte XAML Namespace (x:) Recursos de Linguagem. Para extensões de marcação específicas do WPF, consulte Extensões XAML do WPF .

Propriedades anexadas

As propriedades anexadas são um conceito de programação introduzido em XAML pelo qual as propriedades podem ser de propriedade e definidas por um tipo específico, mas definidas como atributos ou elementos de propriedade em qualquer elemento. O cenário principal para o qual as propriedades anexadas se destinam é habilitar elementos filho em uma estrutura de marcação para relatar informações a um elemento pai sem exigir um modelo de objeto amplamente compartilhado em todos os elementos. Por outro lado, as propriedades anexadas podem ser usadas por elementos pai para relatar informações a elementos filho. Para obter mais informações sobre a finalidade das propriedades anexadas e como criar suas próprias propriedades anexadas, consulte Visão geral de propriedades anexadas.

As propriedades anexadas usam uma sintaxe que se assemelha superficialmente à sintaxe do elemento de propriedade, especificando também um typeName. propertyName combinação. Há duas diferenças importantes:

  • Você pode usar o typeName.combinação propertyName mesmo ao definir uma propriedade anexada por meio da sintaxe do atributo. As propriedades anexadas são o único caso em que qualificar o nome da propriedade é um requisito em uma sintaxe de atributo.

  • Você também pode usar a sintaxe do elemento de propriedade para propriedades anexadas. No entanto, para a sintaxe de elemento de propriedade típica, o typeName que você especifica é o elemento de objeto que contém o elemento de propriedade. Se você estiver se referindo a uma propriedade anexada, o typeName será a classe que define a propriedade anexada, não o elemento de objeto que contém.

Eventos anexados

Os eventos anexados são outro conceito de programação introduzido em XAML, onde os eventos podem ser definidos por um tipo específico, mas os manipuladores podem ser anexados em qualquer elemento de objeto. Na implementação do WOF, geralmente o tipo que define um evento anexado é um tipo estático que define um serviço e, às vezes, esses eventos anexados são expostos por um alias de evento roteado em tipos que expõem o serviço. Os manipuladores para eventos anexados são especificados por meio da sintaxe do atributo. Assim como acontece com os eventos anexados, a sintaxe do atributo é expandida para eventos anexados para permitir o uso do tipo typeName. eventName, em que typeName é a classe que fornece os acessadores Add e Remove para manipuladores de eventos na infraestrutura de evento anexado e eventName é o nome do evento.

Anatomia de um elemento raiz XAML

A tabela a seguir mostra um elemento raiz XAML típico dividido, mostrando os atributos específicos de um elemento raiz:

Atributo Descrição
<Page Elemento de objeto de abertura do elemento raiz
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" O namespace XAML padrão (WPF)
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" O namespace XAML da linguagem XAML
x:Class="ExampleNamespace.ExampleCode" A declaração de classe parcial que conecta a marcação a qualquer código associado definido para a classe parcial
> Fim do elemento de objeto da raiz. O objeto ainda está aberto porque o elemento possui elementos subordinados.

Usos XAML opcionais e não recomendados

As seções a seguir descrevem os usos XAML tecnicamente compatíveis com processadores XAML, mas que produzem verbosidade ou outros problemas estéticos que interferem nos arquivos XAML que permanecem legíveis por humanos ao desenvolver aplicativos que contêm fontes XAML.

Usos de elementos de propriedade opcionais

Os usos de elementos de propriedade opcionais incluem escrever explicitamente as propriedades de conteúdo do elemento que o processador XAML considera implícitas. Por exemplo, ao declarar o conteúdo de um Menu, você pode optar por declarar explicitamente a coleção Items do Menu como um tag de elemento de propriedade <Menu.Items> e colocar cada MenuItem dentro de <Menu.Items>, em vez de usar o comportamento implícito do processador XAML, onde todos os elementos filhos de um Menu devem ser um MenuItem e são colocados na coleção Items. Às vezes, os usos opcionais podem ajudar a esclarecer visualmente a estrutura do objeto, conforme representado na marcação. Ou, às vezes, o uso explícito de um elemento de propriedade pode evitar uma marcação que é tecnicamente funcional, mas visualmente confusa, como extensões de marcação aninhadas dentro de um valor de atributo.

Atributos totalmente qualificados de typeName.memberName

O typeName. O formuláriomemberName para um atributo funciona de forma mais ampla do que apenas no caso de um evento roteado. Mas em outras situações essa forma é supérflua e você deve evitá-la, mesmo que apenas por motivos de estilo de marcação e legibilidade. No exemplo a seguir, cada uma das três referências ao atributo Background é completamente equivalente:

<Button Background="Blue">Background</Button>
<Button Button.Background="Blue">Button.Background</Button>
<Button Control.Background="Blue">Control.Background</Button>

Button.Background funciona porque a consulta qualificada para essa propriedade em Button é bem-sucedida (Background foi herdada de Control) e Button é a classe do elemento de objeto ou de uma classe base. Control.Background funciona porque a classe Control realmente define Background e Control é uma classe base Button.

No entanto, o seguinte typeName: o exemplo de formuláriomemberName não funciona e, portanto, é mostrado comentado.

<!--<Button Label.Background="Blue">Does not work</Button> -->

Label é outra classe derivada de Controle, se você tivesse especificado Label.Background dentro de um elemento de objeto Label, esse uso teria funcionado. No entanto, como Label não é a classe ou classe base de Button, o comportamento do processador XAML especificado é processar Label.Background como uma propriedade anexada. Label.Background não é uma propriedade anexada disponível e esse uso falha.

Elementos da propriedade baseTypeName.memberName

De forma análoga a como o typeName.memberName funciona para sintaxe de atributo, a sintaxe baseTypeName.memberName funciona para a sintaxe do elemento de propriedade. Por exemplo, a sintaxe a seguir funciona:

<Button>Control.Background PE
  <Control.Background>
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
      <GradientStop Color="Yellow" Offset="0.0" />
      <GradientStop Color="LimeGreen" Offset="1.0" />
    </LinearGradientBrush>
    </Control.Background>
</Button>

Aqui, o elemento de propriedade foi fornecido como Control.Background mesmo que o elemento de propriedade estivesse contido em Button.

Mas assim como typeName.formulário memberName para atributos, baseTypeName.memberName é um estilo ruim na marcação e você deve evitá-lo.

Consulte também