Compartilhar 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] no 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 considerar o 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 instanciar uma representação em tempo de execução quando o XAML para WPF é analisado. 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 classe

Propriedades e eventos que aparecem como membros do XAML de um tipo WPF geralmente são herdados de tipos base. Por exemplo, considere este exemplo: <Button Background="Blue" .../>. A propriedade Background não é imediatamente declarada na classe Button, se você 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 representa uma mudança significativa em relação a uma interpretação baseada em 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 'object'

A sintaxe do elemento objeto é a sintaxe de marcação XAML que cria uma instância de uma classe CLR ou estrutura declarando 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 name="value". 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 o tag 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 equilíbrio e aninhamento adequados com outros pares de tags de abertura e fechamento.

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

Por exemplo, o exemplo a seguir é a sintaxe de elemento de objeto que cria uma instância nova da Button classe e também especifica um Name atributo 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 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 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 de 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.

Observação

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 cadeia de caracteres 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 e 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 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 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 ao invés 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 atributo TypeConverterou o tipo de valor dessa propriedade for declarado com um atributo TypeConverter, 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, será tentada uma conversão direta para o tipo de propriedade. 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 não-flag, o comportamento nativo é processar a cadeia de caracteres de um valor de atributo e resolvê-la em um dos valores de enumeração. Você não especifica a enumeração no formato Enumeração.Valor, como faz no código. Em vez disso, você especifica apenas o Valor e a Enumeração é inferida pelo tipo da propriedade que você está definindo. Se você especificar um atributo na Enumeração. Formulário de 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 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 um Trigger que atue em várias condições de uma enumeração nonflag:

<!--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 Glyphs classe; 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 ModifierKeys enumeração 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 nomes de membros de eventos

Ao especificar um atributo, você pode referenciar qualquer propriedade ou evento que exista como um membro do tipo CLR instanciado para o elemento de objeto que 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 qualquer objeto acessível por meio do namespace padrão usando um nome qualificado parcial do tipo typeName.event; essa sintaxe dá suporte à anexação de manipuladores para eventos roteados, quando o manipulador tem como objetivo gerenciar o roteamento de eventos provenientes de elementos filhos, mas o elemento pai não possui 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 no formulário 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 PropertyPath classe 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

A sintaxe do elemento de propriedade é 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, a propriedade é especificada usando uma tag de abertura no formato elementTypeName.propertyName, o valor da propriedade é especificado dentro e, em seguida, o elemento de 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 e, 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 a mesma combinação de elementTypeName.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 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 do 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 o processamento de espaço em branco em XAML). Outro cenário é para que a 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 de coleções

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:

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 destinados a se tornar itens da coleção são especificados como um ou mais elementos filhos do elemento de propriedade. Cada item desse tipo é avaliado como um objeto durante o carregamento e adicionado à coleção ao chamar o método Add da coleção implícita. Por exemplo, a propriedade Triggers de Style utiliza 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, especifique um ou mais Trigger itens como elementos dentro do elemento de propriedade Style.Triggers, onde Trigger (ou uma classe derivada) é o tipo esperado como tipo de item para o TriggerCollection, que é fortemente 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.

Observação

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 List<T> classe como uma classe base, pois ela implementa IList diretamente ou Dictionary<TKey,TValue> como uma classe base, porque ela implementa IDictionary diretamente.

Nas páginas de referência do .NET para tipos de coleção, essa sintaxe com a deleção intencional 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 aninhado como um elemento filho de outro elemento se enquadra em um ou ambos os seguintes casos: um membro de uma propriedade de coleção implícita do elemento pai ou um elemento que especifica o valor da propriedade de conteúdo XAML para o elemento pai (as propriedades de conteúdo XAML serão discutidas em uma seção futura). Em outras palavras, a relação de elementos pai e elementos filho em uma página de marcação é realmente um único objeto na raiz, e cada elemento de objeto abaixo da raiz é uma única instância 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 mostrado Triggers 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 tenha um construtor sem parâmetros.

Propriedades de conteúdo XAML

A sintaxe de conteúdo do XAML é uma sintaxe que só está habilitada em classes que especificam ContentPropertyAttribute como parte da declaração de classe. Faz ContentPropertyAttribute 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/verbosa tem um valor ocasional para clareza de 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 para que elementos que estão intuitivamente relacionados como pai-filho possam ser aninhados diretamente. Etiquetas de elemento de propriedade para outras propriedades em um elemento não são atribuídas como "conteúdo" por uma estrita definição da linguagem XAML; elas são previamente processadas na 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, o código a seguir não é analisado:

<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 ocorre se a propriedade de conteúdo for uma coleção, e os elementos filho forem intercalados com elementos pertencentes à 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 ao conteúdo. Veja a seguir a sintaxe de conteúdo de uma Panel classe derivada. Todas as Panel classes derivadas estabelecem a propriedade de conteúdo XAML para ser Children, o que requer um valor de 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ínuos 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 de objeto filho 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 uma grande quantidade de espaço em branco será difícil de detectar visualmente na marcação se os elementos de propriedade estiverem intercalados com o 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 um elemento de objeto para instanciar a classe Example, em que o namespace CLR que contém essa classe (e possivelmente as informações do assembly externo que contêm tipos subjacentes) foi mapeado anteriormente para o prefixo custom.

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

Extensões de marcação

O XAML define uma extensão de marcação que permite escapar do tratamento normal do processador XAML de valores de atributos de cadeia de caracteres ou elementos de objeto e adia o processamento para uma classe subjacente. 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 de colchete seja encontrada.

A implementação do .NET XAML usa a MarkupExtension classe abstrata 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 simples vinculação de dados em WPF é realizada ao especificar a extensão de marca {Binding} no lugar do valor que uma determinada propriedade assumiria normalmente. 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 Style objeto é 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 da propriedade para uma pesquisa de recurso e permite fornecer o valor da propriedade Style, do tipo Style, na sintaxe do atributo como no exemplo a seguir:

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

Aqui, StaticResource identifica a StaticResourceExtension classe 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 StaticResourceExtension , em que o parâmetro, conforme retirado da cadeia de caracteres de extensão, declara o solicitado ResourceKey. MyStyle espera-se que seja o valor x:Key de um Style definido como um recurso. O uso da Extensão de Marcação StaticResource requer que o recurso seja usado para fornecer o valor da Style propriedade por meio da lógica de pesquisa 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 XAML do 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 os recursos de linguagem XAML Namespace (x:). 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 a que se destinam as propriedades anexadas é permitir que elementos filhos em uma estrutura de marcação relatem informações a um elemento pai sem exigir um modelo de objeto extensamente compartilhado entre todos os elementos. Por outro lado, as propriedades anexadas podem ser usadas por elementos pai para comunicar informações a elementos filhos. 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, na qual você também especifica uma combinação de `typeName` e `propertyName`. Há duas diferenças importantes:

  • Você pode usar a combinação typeName.propertyName mesmo ao definir uma propriedade anexada usando a sintaxe de 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 típica do elemento de propriedade, o typeName especificado é 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 um uso de typeName.eventName, em que typeName é a classe que fornece Add e Remove acessadores de manipulador de eventos para a infraestrutura de evento anexada, 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 Abertura do elemento de objeto 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-behind definido para a classe parcial
> Fim do elemento de objeto para a raiz. O objeto ainda não foi fechado porque o elemento contém elementos filho

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 uma marca 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. Às vezes, o uso de um elemento de propriedade explícito 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 qualificados de typeName.memberName completos

O formato typeName.memberName para um atributo funciona de forma mais abrangente do que apenas no caso de 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 Background atributo é 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 verificação qualificada dessa 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 Control classe realmente define Background e Control é uma Button classe base.

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

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

Label é outra classe derivada de Control, e se você tivesse especificado Label.Background dentro de um Label elemento de objeto, esse uso teria funcionado. No entanto, como Label não é a classe ou a classe base de Button, o comportamento especificado do processador XAML é então 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 a sintaxe typeName.memberName funciona para atributos, a sintaxe baseTypeName.memberName funciona para elementos 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 dado como Control.Background, mesmo que o elemento de propriedade estivesse contido em Button.

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

Consulte também