Sintaxe XAML em detalhes

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

Especificação da Linguagem XAML

A terminologia de 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 regras estruturais do XML. Parte da terminologia é compartilhada com ou se baseia na terminologia usada com frequência ao descrever a linguagem XML ou o modelo de objeto do documento XML.

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

XAML e CLR

XAML é uma linguagem de marcação. O CLR (Common Language Runtime), como implícito por seu nome, permite a execução em tempo de execução. XAML por si só não é uma das linguagens comuns diretamente consumidas pelo runtime de CLR. Em vez disso, você pode pensar em XAML como dando suporte a seu próprio sistema de tipos. O sistema de análise de XAML específico que é usado pelo WPF se baseia no CLR e o sistema de tipos do CLR. Tipos XAML são mapeados para tipos do CLR para instanciar uma representação de tempo de execução quando o XAML para WPF é analisado. Por esse motivo, o restante da discussão de sintaxe neste documento incluirá referências ao sistema de tipos do CLR, embora as discussões de sintaxe equivalentes na especificação da linguagem XAML não o façam. (Segundo o nível de especificação da linguagem XAML, tipos de XAML podem ser mapeados para qualquer outro sistema de tipos, o que significa que esse sistema não precisa ser o CLR; no entanto, isso exigiria a criação e uso de um analisador XAML diferente.)

Membros de tipos e herança de classe

Propriedades e eventos como eles aparecem como membros XAML de um tipo WPF são frequentemente herdados de tipos base. Considere este exemplo: <Button Background="Blue" .../>. A Background propriedade não é uma propriedade declarada imediatamente na Button classe, se você for 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 dos elementos XAML do WPF é uma mudança significativa de 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 interfaces estão envolvidas. Essa é uma razão pela qual 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 o formato DTD ou XSD. Outro motivo é que os recursos de extensibilidade e mapeamento de tipo da própria linguagem XAML impedem a integridade de qualquer representação fixa dos tipos e membros permitidos.

Sintaxe de elemento de objeto

Sintaxe de elemento de objeto é a sintaxe de marcação XAML que instancia uma estrutura ou classe CLR pela declaração de um elemento XML. Essa sintaxe é semelhante à sintaxe de outras linguagens de marcação como HTML. A sintaxe de elemento de objeto começa com um colchete angular esquerdo (<), seguido imediatamente do nome do tipo da classe ou estrutura sendo instanciada. Zero ou mais espaços podem seguir o nome do tipo e zero ou mais atributos podem também ser declarados no elemento de objeto, com um ou mais espaços separando o par nome="valor" de cada atributo. Por fim, uma das seguintes condições deve ser verdadeira:

  • O elemento e a etiqueta devem ser fechados por uma barra (/) seguida imediatamente por um colchete angular reto (>).

  • A etiqueta de abertura deve ser completada por um colchete angular reto (>). Outros elementos de objeto, elementos de propriedade ou texto interno podem vir após a marca de abertura. Exatamente que conteúdo pode estar contido aqui é normalmente restrito pelo modelo de objeto do elemento. A marca de fechamento equivalente para o elemento de objeto também deve existir, com aninhamento e equilíbrio adequados em relação a outros pares de marca de abertura e fechamento.

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

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

<Button Name="CheckoutButton"/>

O exemplo a seguir é uma sintaxe de elemento de objeto que também inclui a sintaxe de propriedade de conteúdo XAML. O texto interno contido dentro será usado para definir a TextBox propriedade de conteúdo XAML, 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 da sintaxe, mas esse elemento só funcionará corretamente em um aplicativo ou página quando ele for colocado em uma posição esperada de uma árvore de elementos ou modelo de conteúdo geral. Por exemplo, um MenuItem normalmente só deve ser colocado como filho de uma MenuBase classe derivada, como Menu. Os modelos de conteúdo para elementos específicos são documentados como parte dos comentários nas páginas de classe para controles e outras classes WPF que podem ser usadas como elementos XAML.

Propriedades de elementos de objeto

Propriedades em XAML são definidas por uma variedade de sintaxes possíveis. Qual sintaxe pode ser usada para uma determinada propriedade é algo que varia com base nas características do sistema de tipos subjacente da propriedade que você está configurando.

configurando valores de propriedades, você adiciona recursos ou características a objetos que existem no grafo de objeto em tempo de execução. O estado inicial do objeto criado a partir de um elemento de objeto é baseado no comportamento do construtor sem parâmetros. Normalmente, seu aplicativo usará algo diferente de uma instância completamente padronizada de um determinado objeto.

Sintaxe de atributo (Propriedades)

Sintaxe de 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 dá suporte ao 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.

Observação

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

Para ser configurada via sintaxe de atributo, uma propriedade deve ser pública e deve ser gravável. O valor da propriedade no sistema de tipos de suporte 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 de suporte relevante.

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

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

Processamento de valores de atributo

O valor de cadeia de caracteres dentro das aspas de abertura e fechamento é processado por um processador XAML. Para propriedades, o comportamento padrão de processamento é 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 derivado do , 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 MarkupExtensionmarcaçã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 então uma expressão que adia a avaliação até o tempo de execução, mas não será um objeto recém-instanciado.

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

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

Valores de atributo de enumeração

Enumerações em XAML são processadas intrinsecamente pelos analisadores XAML e os membros de uma enumeração devem ser definidos especificando-se o nome da cadeia de caracteres de uma das constantes nomeadas da enumeração.

Para valores de enumeração não sinalizadores, o comportamento nativo é processar a cadeia de caracteres de um valor de atributo e resolvê-lo para um dos valores de enumeração. Você não especifica a enumeração no formato Enumeração.Valor, do modo como você faz no código. Em vez disso, você especifica somente Valor, enquanto Enumeração é inferido pelo tipo da propriedade você está configurando. Se você especificar um atributo no formato Enumeração.Valor, ele não será resolvido corretamente.

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

<!--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 no XAML são raras no WPF. No entanto, uma dessas enumerações é StyleSimulations. Você poderia, por exemplo, usar a sintaxe de atributo flagwise delimitada por vírgulas para modificar o exemplo fornecido nos Comentários para a Glyphs classe; StyleSimulations = "BoldSimulation"StyleSimulations = "BoldSimulation,ItalicSimulation" KeyBinding.Modifiers é outra propriedade onde mais de um valor de enumeração pode ser especificado. No entanto, essa propriedade acontece para ser um caso especial, porque a enumeração oferece suporte a ModifierKeys 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 teclas na programação do Microsoft Windows, como "Ctrl + Alt".

Propriedades e referências de nome de membro de evento

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

Ou você pode fazer referência a uma propriedade anexada ou evento anexado, independente do elemento de objeto que o contém. (Propriedades anexadas são discutidas em uma seção posterior).

Você também pode nomear qualquer evento de qualquer objeto que possa ser acessado através do namespace padrão usando um nome parcialmente qualificado typeName.evento; essa sintaxe dá suporte à anexação de manipuladores para eventos roteados em que o manipulador destina-se a manipular o roteamento de eventos de elementos filho, mas o elemento pai também não tem esse evento em sua tabela de membros. Essa sintaxe é semelhante a uma sintaxe de evento anexado, mas o evento aqui não é um evento anexado verdadeiro. Em vez disso, você está referenciando um evento com um nome qualificado. Para obter mais informações, consulte Visão geral de eventos roteados.

Em 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 no formato 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 sendo definida ou os comportamentos de subsistemas do 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 vinculação de dados e para destinos de storyboard e é habilitado PropertyPath pela classe e seu conversor de tipo. Para obter uma descrição mais completa da semântica de pesquisa, consulte Sintaxe XAML PropertyPath.

Sintaxe de elemento de propriedade

Sintaxe de elemento de propriedade é uma sintaxe que diverge um pouco das regras de sintaxe XML básicas para elementos. Em 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. Em XAML, você pode atribuir outros elementos de objeto para serem o valor de uma propriedade. Essa funcionalidade é habilitada pela sintaxe de elemento de propriedade. Em vez de a propriedade ser especificada como um atributo na marca de elemento, a propriedade é especificada usando uma marca de elemento de abertura na forma elementTypeName.propertyName, o valor da propriedade é especificado ali e então o elemento de propriedade é fechado.

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

Por exemplo, a sintaxe do elemento de propriedade a seguir está a ContextMenu propriedade de um Buttonarquivo .

<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 dado 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 da interface do usuário, e elementos de espaço em branco específicos, 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 feeds de linha, mas a sintaxe de elemento de propriedade pode, desde que a preservação significativa de espaço em branco esteja ativa (para obter detalhes, consulte Processamento de espaço em branco em XAML). Outro cenário é aquele no qual a Política x:Uid pode ser aplicada ao elemento de propriedade e, portanto, marca o valor dentro dele como um valor que deve ser localizado BAML de saída do no 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 disponha do suporte de uma instância ou objeto. (Para obter detalhes sobre o conceito de árvore lógica, consulte Árvores no WPF.)

Para propriedades em que a sintaxe de atributo e elemento de propriedade é suportada, as duas sintaxes geralmente têm o mesmo resultado, embora sutilezas como manipulação de espaço em branco possam variar ligeiramente entre as sintaxes.

Sintaxe de coleção

A especificação da linguagem XAML requer implementações de processador XAML para identificar propriedades nas quais o tipo de valor é uma coleção. A implementação geral de processador XAML no .NET é baseada em código gerenciado e no CLR e identifica os tipos de coleção por meio de um dos seguintes:

Se o tipo de uma propriedade é uma coleção, o tipo da coleção inferido não precisa ser especificado na marcação como um elemento de objeto. Em vez disso, os elementos a se tornarem itens na coleção são especificados como um ou mais elementos filho do elemento de propriedade. Cada um desses itens é avaliado para um objeto durante o carregamento e adicionado à coleção chamando o método Add da coleção implícita. Por exemplo, a Triggers propriedade de usa o tipo TriggerCollectionde Style coleção especializada , que implementa IList. Não é necessário instanciar um TriggerCollection elemento de objeto na marcação. Em vez disso, você especifica um ou mais Trigger itens como elementos dentro do Style.Triggers elemento de propriedade, onde Trigger (ou uma classe derivada) é o tipo esperado como o tipo de item para o fortemente tipado e implícito TriggerCollection.

<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 tanto um tipo de coleção quanto a propriedade de conteúdo XAML para esse tipo e tipos derivados, o que é abordado 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. Geralmente o construtor do tipo pai faz 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.

Observação

As interfaces genéricas de lista e dicionário (IList<T> e IDictionary<TKey,TValue>) não são suportadas para detecção de coleção. No entanto, você pode usar a List<T> classe como uma classe base, porque ela implementa diretamente, ou Dictionary<TKey,TValue> como uma classe base, porque ela implementa IListIDictionary diretamente.

Nas páginas de referência do .NET para tipos de coleção, essa sintaxe com a omissão deliberada do elemento de objeto para uma coleção é ocasionalmente mencionada nas seções de sintaxe XAML como sintaxe de coleção implícita.

Com exceção do elemento raiz, cada elemento de objeto em um arquivo XAML que está aninhado como um elemento filho de outro elemento é na realidade um elemento que se enquadra em um ou ambos os casos a seguir: um membro de uma propriedade de coleção implícita do seu elemento pai ou então um elemento que especifica o valor da propriedade de conteúdo XAML para o elemento pai (propriedades de conteúdo XAML serão discutidas em uma seção posterior). Em outras palavras, a relação dos elementos pai e filho em uma página de marcação é na verdade um único objeto na raiz, sendo que todo elemento de objeto abaixo da raiz é uma instância única que fornece um valor da propriedade do pai ou então é um dos itens dentro de uma coleção que é também um valor da propriedade de tipo de 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 object 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 mostrado Triggers anteriormente falharia. Declarar explicitamente a coleção requer que a classe de coleção deve oferecer suporte a um construtor sem parâmetros e TriggerCollection não tem um construtor sem parâmetro.

Propriedades de conteúdo XAML

A sintaxe de conteúdo XAML é uma sintaxe habilitada somente 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 content desse tipo de elemento (incluindo classes derivadas). Quando processados por um processador XAML, quaisquer elementos filho ou texto interno que sejam encontrados entre as marcas de abertura e fechamento do elemento de objeto serão atribuídos como sendo o valor da propriedade de conteúdo XAML para esse 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 do .NET. A técnica explícita/detalhada tem valor ocasional para fins de esclarecimento de marcação ou como uma questão de estilo de marcação, mas a intenção de uma propriedade de conteúdo costuma ser simplificar a marcação para que os elementos relacionados intuitivamente como pai/filho possam ser diretamente aninhados. Marcas de elemento de propriedade para outras propriedades em um elemento não são atribuídas como "conteúdo" segundo uma definição estrita de linguagem XAML; eles são processados anteriormente na ordem de processamento do analisador XAML e não são considerados "conteúdo".

Valores de 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 todos os outros elementos de propriedade nesse elemento de objeto. Isso é verdadeiro 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 analisa:

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

Isso é ilegal essencialmente porque se essa sintaxe tivesse sido tornada explícita usando sintaxe de 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 similarmente ilegal é no caso de a propriedade de conteúdo ser uma coleção e elementos filho serem intercalados 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 combinados

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 tem uma propriedade de conteúdo XAML e o tipo da propriedade de conteúdo XAML é uma coleção, o tipo de coleção sugerido não precisa ser especificado na marcação como um elemento de objeto e a propriedade de conteúdo XAML não precisa 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 o conteúdo. A seguir está a sintaxe de conteúdo para uma Panel classe derivada. Todas as Panel classes derivadas estabelecem a propriedade de conteúdo XAML como Children, 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 nem o elemento para Children o UIElementCollection é necessário na marcação. Esse é um recurso de design do XAML para que os elementos contidos recursivamente que definem uma interface do usuário sejam representados de forma mais intuitiva como uma árvore de elementos aninhados com relações imediatas de elementos pai-filho, sem intervir marcas de elemento de propriedade ou objetos de coleção. Na verdade, não pode ser especificado explicitamente na marcação como um elemento de objeto, UIElementCollection por design. Como seu único uso pretendido é como uma coleção implícita, não expõe um construtor sem parâmetros público e, portanto, UIElementCollection não pode ser instanciado como um elemento de objeto.

Combinação de elementos de propriedade e elementos de objeto em um objeto com uma propriedade de conteúdo

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

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

Este requisito de ordem de elementos 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, porque espaço em branco significativo será difícil de detectar visualmente na marcação se os elementos de propriedade forem intercalados com texto interno.

Namespaces XAML

Nenhum dos exemplos de sintaxe anteriores especificaram um namespace XAML diferente do namespace XAML padrão. Em aplicativos WPF típicos, o namespace XAML padrão é especificado para ser o namespace WPF. Você pode especificar namespaces XAML diferentes do namespace XAML padrão e ainda assim usar uma sintaxe semelhante. Mas nesse casso, em qualquer lugar em que for nomeada uma classe não acessível dentro do namespace XAML padrão, esse nome de classe deverá ser precedido do 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, em que o namespace CLR que contém essa classe (e possivelmente as informações de assembly externo que contêm tipos de suporte) foi anteriormente mapeado para o prefixo custom.

Para obter mais informações sobre namespaces XAML, consulte Namespaces XAML e mapeamento de namespace para XAML WPF.

Extensões de marcação

O XAML define uma entidade de programação de extensão de marcação que habilita um escape da manipulação normal de valores de atributo de cadeia de caracteres ou elementos de objeto pelo processador XAML e adia o processamento para uma classe de suporte. O caractere que identifica um 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 fazer referência à classe que oferece o comportamento de extensão específico, em que a referência pode omitir a subcadeia de caracteres "Extension" se essa subcadeia faz parte do verdadeiro nome de classe. Depois disso, pode aparecer um único espaço e, em seguida, cada caractere subsequente é usado como entrada pela implementação de extensão até que a chave de fechamento é encontrada.

A implementação XAML do .NET usa a MarkupExtension classe abstrata como base para todas as extensões de marcação suportadas pelo WPF, bem como outras estruturas ou tecnologias. As extensões de marcação que o WPF implementa especificamente geralmente destinam-se a fornecer um meio de fazer referência a outros objetos existentes ou a 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 aceitaria. Muitas das extensões de marcação do WPF permitem uma sintaxe de atributo para propriedades em que a sintaxe de atributo não seria possível de outra maneira. Por exemplo, um objeto é um Style tipo relativamente complexo que contém uma série aninhada de objetos e propriedades. Os estilos no WPF são normalmente definidos como um recurso em um , e então referenciados por meio de uma das duas extensões de marcação do WPF que solicitam um ResourceDictionaryrecurso. A extensão de marcação adia a avaliação do valor da propriedade para uma pesquisa de recurso e permite fornecer o valor da propriedade, tomando o tipo Style, na sintaxe de Style atributo, como no exemplo a seguir:

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

Aqui, StaticResource identifica a classe que fornece a StaticResourceExtension implementação da extensão de marcação. A próxima cadeia de caracteres é usada como a entrada para o construtor não padrãoStaticResourceExtension, onde o parâmetro retirado da cadeia de caracteres MyStyle de extensão declara o solicitado ResourceKey. MyStyle espera-se que seja o valor x:Key de um definido como um Style recurso. O uso da Extensão de Marcação StaticResource solicita que o recurso seja usado para fornecer o valor da propriedade por meio da Style lógica de pesquisa de recurso estático no momento do carregamento.

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

Propriedades Anexadas

Propriedades anexadas são um conceito de programação introduzido no XAML no qual propriedades podem pertencer a um determinado tipo ou ser definidas por ele, mas definidas como atributos ou elementos de propriedade em qualquer elemento. O cenário principal para o qual 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 entre todos os elementos. Por outro lado, propriedades anexadas podem ser usadas pelos elementos pai para relatar informações para elementos filhos. Para obter mais informações sobre o objetivo de propriedades anexadas e como criar suas próprias propriedades anexadas, consulte Visão geral das propriedades anexadas.

Propriedades anexadas utilizam uma sintaxe que superficialmente se assemelha à sintaxe de elemento de propriedade, em que você também especifica uma combinação typeName.propertyName. Há duas diferenças importantes:

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

  • Você também pode usar a sintaxe de 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 fazendo referência a uma propriedade anexada, o typeName será a classe que define a propriedade anexada, não o elemento de objeto que a contém.

Eventos Anexados

Eventos anexados são outro conceito de programação introduzido em XAML em que os eventos podem ser definidos por um tipo específico, mas manipuladores podem ser anexados a qualquer elemento de objeto. Na implementação 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. Manipuladores para eventos anexados são especificados pela sintaxe de atributo. Assim como ocorre com eventos anexados, a sintaxe de atributo é expandida para eventos anexados para permitir um uso de typeName.eventName, em que typeName é a classe que fornece os acessadores de manipuladores de eventos Add e Remove para a infraestrutura de evento anexado e eventName é o nome do evento.

Anatomia de um elemento raiz XAML

A tabela a seguir mostra um típico elemento raiz XAML, 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" Namespace XAML de linguagem XAML
x:Class="ExampleNamespace.ExampleCode" A declaração de classe parcial que conecta a marcação a qualquer code-behind definido para a classe parcial
> Final do elemento de objeto para a raiz. Objeto ainda não foi fechado porque o elemento contém elementos filho

Usos de XAML opcionais e não recomendados

As seções a seguir descrevem os usos de XAML que são tecnicamente suportados por processadores XAML, mas que produzem detalhes ou outros problemas estéticos que interferem com os arquivos XAML que permanecem legíveis por humanos quando você desenvolve aplicativos que contêm fontes XAML.

Usos de elemento de propriedade opcional

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

Atributos qualificados typeName.memberName completos

A forma typeName.memberName para um atributo realmente funciona mais universalmente do que apenas para o caso de evento roteado. Em outras situações, no entanto, 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 Background atributo são completamente equivalentes:

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

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

No entanto, exemplo de formato de typeName.memberName a seguir não funciona e, portanto, é mostrado comentado:

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

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

Elementos de propriedade baseTypeName.memberName

De maneira semelhante ao modo como o formulário typeName.memberName funciona para a sintaxe de atributo, uma sintaxe baseTypeName.memberName funciona para a sintaxe de 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, embora o elemento de propriedade estivesse contido em Button.

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

Confira também