Detalles de la sintaxis XAML

En este tema se definen los términos que se usan para describir los elementos de la sintaxis XAML. Estos términos se usan con frecuencia durante el resto de esta documentación, tanto para la documentación de WPF específicamente como para los demás marcos que usan XAML o los conceptos básicos de XAML habilitados por la compatibilidad del lenguaje XAML en el nivel System.Xaml. En este tema se amplía la terminología básica introducida en el tema XAML en WPF.

Especificación del lenguaje XAML

La terminología de la sintaxis XAML que se define aquí también se define o hace referencia en la especificación del lenguaje XAML. XAML es un lenguaje basado en XML y sigue o expande las reglas estructurales de XML. Parte de la terminología se comparte o se basa en la terminología que se usa habitualmente al describir el lenguaje XML o el modelo de objetos de documento XML.

Para obtener más información sobre la especificación del lenguaje XAML, descargue [MS-XAML] en el Centro de descarga de Microsoft.

XAML y CLR

XAML es un lenguaje de marcado. Common Language Runtime (CLR), como se indica en su nombre, permite la ejecución en tiempo de ejecución. XAML por sí mismo no es uno de los lenguajes comunes que el tiempo de ejecución de CLR consume directamente. En su lugar, se puede considerar que XAML respalda su propio sistema de tipos. El sistema de análisis XAML concreto que usa WPF se basa en CLR y en el sistema de tipos CLR. Los tipos XAML se asignan a tipos CLR para crear instancias de una representación en tiempo de ejecución cuando se analiza el XAML para WPF. Por este motivo, el resto de la explicación de la sintaxis de este documento incluirá referencias al sistema de tipos CLR, aunque las discusiones de sintaxis equivalentes en la especificación del lenguaje XAML no lo hagan. (Según el nivel de especificación del lenguaje XAML, los tipos XAML se podrían asignar a cualquier otro sistema de tipos, que no tiene que ser CLR, pero eso requeriría la creación y el uso de un analizador XAML diferente).

Miembros de tipos y herencia de clases

Las propiedades y los eventos tal y como aparecen como miembros XAML de un tipo WPF se suelen heredar de los tipos base. Por ejemplo, considere este ejemplo: <Button Background="Blue" .../>. La propiedad Background no es una propiedad declarada inmediatamente en la clase Button, si fuera a examinar la definición de clase, los resultados de la reflexión o la documentación. En su lugar, Background se hereda de la clase base Control.

El comportamiento de herencia de clases de los elementos XAML de WPF representa una divergencia significativa respecto a una interpretación aplicada por el esquema del marcado XML. La herencia de clases puede ser compleja, especialmente cuando las clases base intermedias son abstractas o cuando las interfaces están implicadas. Este es un motivo por el que es difícil representar con precisión y por completo el conjunto de elementos XAML y sus atributos permitidos mediante los tipos de esquema que se usan normalmente para la programación XML, como el formato DTD o XSD. Otra razón es que las características de extensibilidad y asignación de tipos del propio lenguaje XAML impiden la integridad de cualquier representación fija de los tipos y miembros permitidos.

Sintaxis de elemento de objeto

La sintaxis de elementos de objeto es la sintaxis de marcado XAML que crea una instancia de una clase o estructura CLR declarando un elemento XML. Esta sintaxis es similar a la sintaxis de elemento de otros lenguajes de marcado, como HTML. La sintaxis de elementos de objeto comienza con un corchete angular izquierdo (<), seguido inmediatamente del nombre de tipo de la clase o estructura en la que se crea una instancia. Tras el nombre de tipo pueden aparecer cero o más espacios y también se pueden declarar cero o más atributos en el elemento de objeto, con uno o más espacios que separan cada par de atributo name="value". Por último, debe cumplirse al menos una de las siguientes:

  • El elemento y la etiqueta deben cerrarse mediante una barra diagonal (/) seguida inmediatamente de un corchete angular derecho (>).

  • La etiqueta de apertura debe completarse con un corchete angular recto (>). Otros elementos de objeto, elementos de propiedad o texto interno pueden aparecer tras la etiqueta de apertura. El tipo de contenido que puede contenerse aquí exactamente suele estar restringido por el modelo de objetos del elemento. También debe existir una etiqueta de cierre equivalente para el elemento de objeto para el anidamiento y el equilibrio adecuados con otros pares de etiquetas de apertura y cierre.

XAML implementado mediante .NET tiene un conjunto de reglas que asignan elementos de objeto a tipos, atributos en propiedades o eventos y espacios de nombres XAML a espacios de nombres CLR y ensamblados. Para WPF y .NET, los elementos de objeto XAML se asignan a los tipos de .NET tal como se definen en los ensamblados a los que se hace referencia y los atributos se asignan a los miembros de esos tipos. Cuando hace referencia a un tipo CLR en XAML, también tiene acceso a los miembros heredados de ese tipo.

Por ejemplo, el ejemplo siguiente es la sintaxis de elemento de objeto que crea instancias de una nueva instancia de la clase Button y también especifica un atributo Name y un valor para ese atributo:

<Button Name="CheckoutButton"/>

El ejemplo siguiente es la sintaxis de elemento de objeto que también incluye la sintaxis de la propiedad de contenido XAML. El texto interno que se encuentra dentro se usará para establecer la propiedad de contenido XAML TextBox, Text.

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

Modelos de contenido

Una clase puede admitir un uso como elemento de objeto XAML en términos de sintaxis, pero ese elemento solo funcionará correctamente en una aplicación o página cuando se coloca en una posición esperada de un modelo de contenido general o árbol de elementos. Por ejemplo, un elemento MenuItem normalmente solo debe colocarse como elemento secundario de una clase derivada MenuBase, como Menu. Los modelos de contenido para elementos específicos se documentan como parte de los comentarios de las páginas de clase para los controles y otras clases de WPF que se pueden usar como elementos XAML.

Propiedades de elementos de objeto

Las propiedades de XAML se establecen mediante una variedad de sintaxis posibles. La sintaxis que se puede usar para una propiedad determinada variará en función de las características del sistema de tipos subyacentes de la propiedad que está estableciendo.

Al establecer valores de propiedades, se agregan características a objetos tal como existen en el gráfico de objetos en tiempo de ejecución. El estado inicial del objeto creado a partir de un elemento de objeto se basa en el comportamiento del constructor sin parámetros. Normalmente, la aplicación usará algo distinto de una instancia completamente predeterminada de cualquier objeto determinado.

Sintaxis de atributos (propiedades)

La sintaxis de atributo es la sintaxis de marcado XAML que establece un valor para una propiedad declarando un atributo en un elemento de objeto existente. El nombre del atributo debe coincidir con el nombre del miembro CLR de la propiedad de la clase que respalda el elemento de objeto pertinente. El nombre del atributo va seguido de un operador de asignación (=). El valor del atributo debe ser una cadena entre comillas.

Nota:

Puede usar comillas alternas para colocar una comilla literal dentro de un atributo. Por ejemplo, puede usar comillas simples como un medio para declarar una cadena que contenga un carácter de comilla doble dentro de él. Tanto si usa comillas simples como dobles, debe usar un par coincidente para abrir y cerrar la cadena de valor de atributo. También hay secuencias de escape u otras técnicas disponibles para evitar restricciones de caracteres impuestas por cualquier sintaxis XAML determinada. Consulte Entidades de caracteres XML y XAML.

Para establecerse mediante la sintaxis de atributo, una propiedad debe ser pública y debe poder escribirse. El valor de la propiedad en el sistema de tipos de respaldo debe ser un tipo de valor o un tipo de referencia al que un procesador XAML pueda crear una instancia o hacer referencia a él al obtener acceso al tipo de respaldo pertinente.

En el caso de los eventos XAML de WPF, el evento al que se hace referencia como nombre de atributo debe ser público y tener un delegado público.

La propiedad o evento debe ser un miembro de la clase o estructura a la que crea una instancia el elemento de objeto contenedor.

Procesamiento de valores de atributo

Un procesador XAML procesa el valor de cadena contenido dentro de las comillas de apertura y cierre. En el caso de las propiedades, el comportamiento de procesamiento predeterminado viene determinado por el tipo de la propiedad CLR subyacente.

El valor del atributo se rellena mediante uno de los siguientes, con este orden de procesamiento:

  1. Si el procesador XAML encuentra una llave o un elemento de objeto que deriva de MarkupExtension, la extensión de marcado a la que se hace referencia se evalúa primero en lugar de procesar el valor como una cadena y el objeto devuelto por la extensión de marcado se usa como valor. En muchos casos, el objeto devuelto por una extensión de marcado será una referencia a un objeto existente o una expresión que aplaza la evaluación hasta el tiempo de ejecución y no es un objeto recién creado.

  2. Si la propiedad se declara con un atributo TypeConverter, o el tipo de valor de esa propiedad se declara con un atributo TypeConverter, el valor de cadena del atributo se envía al convertidor de tipos como entrada de conversión y el convertidor devolverá una nueva instancia de objeto.

  3. Si no hay TypeConverter, se intenta realizar una conversión directa al tipo de propiedad. Este nivel final es una conversión directa en el valor nativo del analizador entre los tipos primitivos del lenguaje XAML o una comprobación de los nombres de las constantes con nombre en una enumeración (el analizador obtiene acceso a los valores coincidentes).

Valores de atributo de enumeración

Los analizadores XAML procesan intrínsecamente las enumeraciones en XAML y los miembros de una enumeración deben especificarse con el nombre de cadena de una de las constantes con nombre de la enumeración.

En el caso de los valores de enumeración sin marca, el comportamiento nativo es procesar la cadena de un valor de atributo y resolverlo en uno de los valores de enumeración. No se especifica la enumeración con el formato Enumeración.Valor, como lo hace en el código. En su lugar, solo se especifica Valor y Enumeración se deduce por el tipo de la propiedad que está estableciendo. Si especifica un atributo en el formato Enumeración.Valor, no se resolverá correctamente.

En el caso de las enumeraciones con marca, el comportamiento se basa en el método Enum.Parse. Puede especificar varios valores para una enumeración basada en marcas separando cada valor con una coma. Sin embargo, no se pueden combinar valores de enumeración que no sean basados en marcas. Por ejemplo, no se puede usar la sintaxis de coma para intentar crear un objeto Trigger que actúe en varias condiciones de una enumeración que no sea basada en marcas:

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

Las enumeraciones basadas en marcas que admiten atributos que se pueden establecer en XAML son poco frecuentes en WPF. Sin embargo, una de estas enumeraciones es StyleSimulations. Por ejemplo, podría usar la sintaxis de atributo basada en marcas delimitada por comas para modificar el ejemplo proporcionado en comentarios para la clase Glyphs; StyleSimulations = "BoldSimulation" podría convertirse en StyleSimulations = "BoldSimulation,ItalicSimulation". KeyBinding.Modifiers es otra propiedad donde se puede especificar más de un valor de enumeración. Sin embargo, esta propiedad es un caso especial, ya que la enumeración ModifierKeys admite su propio convertidor de tipos. El convertidor de tipos para modificadores usa un signo más (+) como delimitador en lugar de una coma (,). Esta conversión admite la sintaxis más tradicional para representar combinaciones de teclas en programación de Microsoft Windows, como "Ctrl+Alt".

Propiedades y referencias de nombre de miembro de eventos

Al especificar un atributo, puede hacer referencia a cualquier propiedad o evento que exista como miembro del tipo CLR al que creó una instancia para el elemento de objeto contenedor.

O bien, puede hacer referencia a una propiedad adjunta o un evento adjunto, independientemente del elemento de objeto contenedor. (Las propiedades adjuntas se describen en una sección que aparecerá a continuación).

También puede asignar un nombre a cualquier evento desde cualquier objeto al que se pueda acceder mediante el espacio de nombres predeterminado con un nombre parcialmente completo nombreDeTipo.evento; esta sintaxis admite la asociación de controladores para eventos enrutados en los que el controlador está diseñado para controlar el enrutamiento de eventos desde elementos secundarios, pero el elemento primario tampoco tiene ese evento en su tabla de miembros. Esta sintaxis es similar a una sintaxis de evento adjunta, pero el evento aquí no es un verdadero evento adjunto. En su lugar, hace referencia a un evento con un nombre completo. Para obtener más información, vea Información general sobre eventos enrutados.

En algunos escenarios, los nombres de propiedad a veces se proporcionan como el valor de un atributo, en lugar del nombre del atributo. Ese nombre de propiedad también puede incluir calificadores, como la propiedad especificada en el formato tipoDePropietario.nombreDePropiedadDeDependencia. Este escenario es común al escribir estilos o plantillas en XAML. Las reglas de procesamiento de los nombres de propiedad proporcionados como un valor de atributo son diferentes y se rigen por el tipo de la propiedad que se establece o por los comportamientos de determinados subsistemas de WPF. Por obtener más información, consulte Aplicar estilos y plantillas.

Otro uso de los nombres de propiedad es cuando un valor de atributo describe una relación de propiedad y propiedad. Esta característica se usa para el enlace de datos y para los destinos de guion gráfico, y está habilitada por la clase PropertyPath y su convertidor de tipos. Para obtener una descripción más completa de la semántica de búsqueda, consulte Sintaxis de PropertyPath de XAML.

Sintaxis de elementos de propiedad

La sintaxis del elemento de propiedad es una sintaxis que difiere algo de las reglas de sintaxis XML básicas de los elementos. En XML, el valor de un atributo es una cadena de facto, la única variación posible es el formato de codificación de cadena que se está usando. En XAML, puede asignar otros elementos de objeto para que sean el valor de una propiedad. Esta funcionalidad la habilita la sintaxis del elemento de propiedad. En lugar de la propiedad que se especifica como un atributo dentro de la etiqueta de elemento, la propiedad se especifica mediante una etiqueta de elemento de apertura en el formato nombreDeTipoDeElemento.nombreDePropiedad, el valor de la propiedad se especifica dentro y, a continuación, se cierra el elemento de propiedad.

En concreto, la sintaxis comienza con un corchete angular izquierdo (<), seguido inmediatamente por el nombre de tipo de la clase o estructura dentro de la sintaxis del elemento de propiedad. Esto va seguido inmediatamente de un solo punto (.) y, luego, por el nombre de una propiedad y, a continuación, por un corchete angular derecho (>). Al igual que con la sintaxis de atributo, esa propiedad debe existir dentro de los miembros públicos declarados del tipo especificado. El valor que se va a asignar a la propiedad está incluido en el elemento de propiedad. Normalmente, el valor se da como uno o varios elementos de objeto, ya que especificar objetos como valores es el escenario que la sintaxis del elemento de propiedad ha sido diseñada para abordarlo. Por último, se debe proporcionar una etiqueta de cierre equivalente que especifica la misma combinación nombreDeTipoDeElemento.nombreDePropiedad, en el anidamiento y el equilibrio adecuados con otras etiquetas de elemento.

Por ejemplo, a continuación puede verse la sintaxis de elemento de propiedad para la propiedad ContextMenu de Button.

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

El valor de un elemento de propiedad también se puede proporcionar como texto interno, en los casos en los que el tipo de propiedad que se especifica es un tipo de valor primitivo, como String, o una enumeración donde se especifica un nombre. Estos dos usos son algo poco comunes, ya que cada uno de estos casos también podría usar una sintaxis de atributo más sencilla. Un escenario en el que se rellena un elemento de propiedad con una cadena es con las propiedades que no son la propiedad de contenido XAML, pero que todavía se usan para la representación del texto de la interfaz de usuario, y se requieren elementos de espacio en blanco concretos, como saltos de línea, para que aparezcan en ese texto de la interfaz de usuario. La sintaxis de atributo no puede conservar los saltos de línea, pero la sintaxis del elemento de propiedad puede, siempre que la conservación significativa del espacio en blanco esté activa (para obtener más información, consulte Procesamiento de espacios en blanco en XAML). Otro escenario es para que la directiva x:Uid se pueda aplicar al elemento de propiedad y, por tanto, marcar el valor de dentro como un valor que se debe localizar en el BAML de salida de WPF o en otras técnicas.

Un elemento de propiedad no se representa en el árbol lógico de WPF. Un elemento de propiedad es simplemente una sintaxis determinada para establecer una propiedad y no es un elemento que tiene una instancia o un objeto que lo respalda. (Para obtener más información sobre el concepto de árbol lógico, consulte Árboles en WPF).

En el caso de las propiedades en las que se admite la sintaxis de atributos y elementos de propiedad, las dos sintaxis suelen tener el mismo resultado, aunque las sutilezas como el control de espacios en blanco pueden variar ligeramente entre sintaxis.

Sintaxis de colecciones

La especificación XAML requiere implementaciones de procesador XAML para identificar las propiedades en las que el tipo de valor es una colección. La implementación general del procesador XAML en .NET se basa en código administrado y CLR, e identifica los tipos de colección mediante uno de los siguientes:

Si el tipo de una propiedad es una colección, no es necesario especificar el tipo de colección inferido en el marcado como un elemento de objeto. En su lugar, los elementos destinados a convertirse en elementos de la colección se especifican como uno o varios elementos secundarios del elemento de propiedad. Cada elemento de este tipo se evalúa como un objeto durante la carga y se agrega a la colección llamando al método Add de la colección implícita. Por ejemplo, la propiedad Triggers de Style toma el tipo de colección especializado TriggerCollection, que implementa IList. No es necesario crear una instancia de un elemento de objeto TriggerCollection en el marcado. En su lugar, se especifican uno o varios elementos Trigger como elementos dentro del elemento de propiedad Style.Triggers, donde Trigger (o una clase derivada) es el tipo esperado como el tipo de elemento para el tipo TriggerCollection fuertemente 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>

Una propiedad puede ser un tipo de colección y la propiedad de contenido XAML para ese tipo y tipos derivados, que se describen en la sección siguiente de este tema.

Un elemento de colección implícito crea un miembro en la representación del árbol lógico, aunque no aparezca en el marcado como un elemento. Normalmente, el constructor del tipo primario realiza la creación de instancias de la colección que es una de sus propiedades y la colección inicialmente vacía forma parte del árbol de objetos.

Nota:

Las interfaces genéricas de lista y diccionario (IList<T> y IDictionary<TKey,TValue>) no se admiten para la detección de colecciones. Pero puede usar la clase List<T> como una clase base, porque implementa IList directamente, o Dictionary<TKey,TValue> como una clase base, porque implementa IDictionary directamente.

En las páginas de referencia de .NET para tipos de colección, esta sintaxis con la omisión deliberada del elemento de objeto de una colección se aprecia ocasionalmente en las secciones de sintaxis XAML como Sintaxis de colección implícita.

Con la excepción del elemento raíz, cada elemento de objeto de un archivo XAML anidado como elemento secundario de otro elemento es realmente un elemento que es uno o ambos de los casos siguientes: un miembro de una propiedad de colección implícita de su elemento primario o un elemento que especifica el valor de la propiedad de contenido XAML del elemento primario (las propiedades de contenido XAML se tratarán en una sección próxima). En otras palabras, la relación de elementos primarios y elementos secundarios en una página de marcado es realmente un único objeto en la raíz, y cada elemento de objeto debajo de la raíz es una sola instancia que proporciona un valor de propiedad del elemento primario o uno de los elementos de una colección que también es un valor de propiedad de tipo de colección del elemento primario. Este concepto de raíz única es común con XML y se refuerza con frecuencia en el comportamiento de las API que cargan XAML como Load.

En el ejemplo siguiente se muestra una sintaxis con el elemento de objeto de una colección (GradientStopCollection) especificada explícitamente.

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

Tenga en cuenta que no siempre es posible declarar explícitamente la colección. Por ejemplo, si se intenta declarar TriggerCollection explícitamente en el ejemplo de Triggers mostrado anteriormente, se produciría un error. La declaración explícita de la colección requiere que la clase de colección admita un constructor sin parámetros y TriggerCollection no tiene un constructor sin parámetros.

Propiedades del contenido XAML

La sintaxis de contenido XAML es una sintaxis que solo está habilitada en las clases que especifican ContentPropertyAttribute como parte de su declaración de clase. ContentPropertyAttribute hace referencia al nombre de propiedad que es la propiedad de contenido de ese tipo de elemento (incluidas las clases derivadas). Cuando un procesador XAML lo procesa, los elementos secundarios o el texto interno que se encuentran entre las etiquetas de apertura y cierre del elemento de objeto se asignarán para que sean el valor de la propiedad de contenido XAML para ese objeto. Puede especificar elementos de propiedad explícitos para la propiedad de contenido, pero este uso no se muestra generalmente en las secciones de sintaxis XAML de la referencia de .NET. La técnica explícita/detallada tiene un valor ocasional para la claridad de marcado o como cuestión de estilo de marcado, pero normalmente la intención de una propiedad de contenido es simplificar el marcado para que los elementos que están intuitivamente relacionados como elementos primarios y secundarios se puedan anidar directamente. Las etiquetas de elemento de propiedad para otras propiedades de un elemento no se asignan como "contenido" por una definición de lenguaje XAML estricta; se procesan anteriormente en el orden de procesamiento del analizador XAML y no se consideran "contenido".

Los valores de propiedad de contenido XAML deben ser contiguos

El valor de una propiedad de contenido de XAML se debe proporcionar exclusivamente antes o después de cualquier otro elemento de propiedad en ese elemento de objeto. Esto es cierto si el valor de una propiedad de contenido XAML se especifica como una cadena o como uno o varios objetos. Por ejemplo, el marcado siguiente no se analiza:

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

Esto no es válido básicamente porque si esta sintaxis se hizo explícita mediante la sintaxis del elemento de propiedad para la propiedad de contenido, la propiedad de contenido se establecería dos veces:

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

Un ejemplo no válido similar es si la propiedad de contenido es una colección y los elementos secundarios se intercalan con elementos de propiedad:

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

Propiedades de contenido y sintaxis de colección combinadas

Para aceptar más de un único elemento de objeto como contenido, el tipo de la propiedad de contenido debe ser específicamente un tipo de colección. De forma similar a la sintaxis de elementos de propiedad para los tipos de colección, un procesador XAML debe identificar los tipos que son tipos de colección. Si un elemento tiene una propiedad de contenido XAML y el tipo de la propiedad de contenido XAML es una colección, no es necesario especificar el tipo de colección implícito en el marcado como un elemento de objeto y no es necesario especificar la propiedad de contenido XAML como un elemento de propiedad. Por lo tanto, el modelo de contenido aparente en el marcado ahora puede tener más de un elemento secundario asignado como contenido. A continuación se muestra la sintaxis de contenido de una clase Panel derivada. Todas las clases Panel derivadas establecen la propiedad de contenido XAML como Children, que requiere un 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>

Tenga en cuenta que no se requiere ni el elemento de propiedad para Children ni para UIElementCollection en el marcado. Se trata de una característica de diseño de XAML para que los elementos contenidos recursivamente que definen una interfaz de usuario se representen de forma más intuitiva como un árbol de elementos anidados con relaciones de elementos primarios y secundarios inmediatos, sin intervención de etiquetas de elemento de propiedad u objetos de colección. De hecho, UIElementCollection no se puede especificar explícitamente en el marcado como un elemento de objeto, por diseño. Dado que su único uso previsto es como una colección implícita, UIElementCollection no expone un constructor sin parámetros público y, por lo tanto, no se puede crear una instancia como un elemento de objeto.

Mezcla de elementos de propiedad y elementos de objeto en un objeto con una propiedad de contenido

La especificación XAML declara que un procesador XAML puede exigir que los elementos de objeto que se usan para rellenar la propiedad de contenido XAML dentro de un elemento de objeto deben ser contiguos y no deben mezclarse. Esta restricción contra la combinación de elementos de propiedad y contenido es aplicada por los procesadores XAML de WPF.

Puede tener un elemento de objeto secundario como primer marcado inmediato dentro de un elemento de objeto. A continuación, puede introducir elementos de propiedad. O bien, puede especificar uno o varios elementos de propiedad y, a continuación, contenido y más elementos de propiedad. Pero una vez que un elemento de propiedad sigue el contenido, no puede introducir ningún contenido adicional, solo puede agregar elementos de propiedad.

Este requisito de orden de elementos de contenido o propiedad no se aplica al texto interno usado como contenido. Sin embargo, sigue siendo un buen estilo de marcado mantener el texto interno contiguo, ya que será difícil detectar visualmente en el marcado un exceso de espacio en blanco si los elementos de propiedad se intercalan con texto interno.

Espacios de nombres XAML

Ninguno de los ejemplos de sintaxis anteriores ha especificado un espacio de nombres XAML distinto del espacio de nombres XAML predeterminado. En las aplicaciones típicas de WPF, se especifica el espacio de nombres XAML predeterminado para que sea el espacio de nombres WPF. Puede especificar espacios de nombres XAML distintos del espacio de nombres XAML predeterminado y seguir usando una sintaxis similar. Sin embargo, en cualquier lugar donde se llame a una clase que no sea accesible dentro del espacio de nombres XAML predeterminado, ese nombre de clase debe ir precedido del prefijo del espacio de nombres XAML como asignado al espacio de nombres CLR correspondiente. Por ejemplo, <custom:Example/> es la sintaxis de elemento de objeto para crear instancias de una instancia de la clase Example, donde el espacio de nombres CLR que contiene esa clase (y posiblemente la información del ensamblado externo que contiene tipos de respaldo) se asignó previamente al prefijo custom.

Para obtener más información sobre espacios de nombres XAML, consulte Espacios de nombres y asignación de espacios de nombres XAML para WPF.

Extensiones de marcado

XAML define una entidad de programación de extensión de marcado que permite apartarse del control normal del procesador XAML de valores de atributo de cadena o elementos de objeto, y aplaza el procesamiento a una clase de respaldo. El carácter que identifica una extensión de marcado a un procesador XAML cuando se usa la sintaxis de atributo es la llave de apertura ({), seguida de cualquier carácter que no sea una llave de cierre (}). La primera cadena que sigue a la llave de apertura debe hacer referencia a la clase que proporciona el comportamiento de extensión determinado, donde la referencia puede omitir la subcadena "Extensión" si esa subcadena forma parte del nombre de la clase verdadera. A partir de entonces, puede aparecer un solo espacio y, a continuación, cada carácter correcto se usa como entrada por la implementación de la extensión, hasta que se encuentra la llave de cierre.

La implementación XAML de .NET usa la clase MarkupExtension abstracta como base para todas las extensiones de marcado admitidas por WPF, así como otros marcos o tecnologías. Las extensiones de marcado que WPF implementa específicamente están diseñadas a menudo para proporcionar un medio para hacer referencia a otros objetos existentes o para hacer referencias diferidas a objetos que se evaluarán en tiempo de ejecución. Por ejemplo, se logra un enlace de datos de WPF simple especificando la extensión de marcado {Binding} en lugar del valor que normalmente tomaría una propiedad determinada. Muchas de las extensiones de marcado de WPF habilitan una sintaxis de atributo para las propiedades en las que, de otra manera, no sería posible una sintaxis de atributo. Por ejemplo, un objeto Style es un tipo relativamente complejo que contiene una serie anidada de objetos y propiedades. Los estilos de WPF se definen normalmente como un recurso en ResourceDictionary y, a continuación, se hace referencia a ellos mediante una de las dos extensiones de marcado de WPF que solicitan un recurso. La extensión de marcado aplaza la evaluación del valor de propiedad en una búsqueda de recursos y permite proporcionar el valor de la propiedad Style, tomando el tipo Style, en la sintaxis de atributo como en el ejemplo siguiente:

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

Aquí, StaticResource identifica la clase StaticResourceExtension que proporciona la implementación de la extensión de marcado. En la cadena siguiente, MyStyle se usa como entrada para el constructor no predeterminado StaticResourceExtension, donde el parámetro tal y como se toma de la cadena de extensión declara el objeto ResourceKey solicitado. Se espera que MyStyle sea el valor x:Key de un objeto Style definido como un recurso. El uso de la extensión de marcado StaticResource solicita que el recurso se use para proporcionar el valor de propiedad Style mediante la lógica de búsqueda de recursos estáticos en tiempo de carga.

Para más información sobre las extensiones de marcado, consulte Extensiones de marcado y XAML de WPF. Para obtener una referencia de las extensiones de marcado y otras características de programación XAML habilitadas en la implementación general de XAML de .NET, consulte Espacio de nombres Características de lenguaje (x:) de espacios de nombres XAML. Para las extensiones de marcado específicas de WPF, consulte Extensiones XAML de WPF.

Propiedades adjuntas

Las propiedades asociadas son un concepto de programación introducido en XAML en el que las propiedades pueden pertenecer y ser definidas por un tipo determinado, pero se establecen como atributos o elementos de propiedad en cualquier elemento. El escenario principal para el que están pensadas las propiedades asociadas es permitir que los elementos secundarios de una estructura de marcado notifiquen información a un elemento primario sin necesidad de un modelo de objetos ampliamente compartido en todos los elementos. Por el contrario, los elementos primarios pueden usar las propiedades asociadas para notificar información a los elementos secundarios. Para obtener más información sobre el propósito de las propiedades asociadas y cómo crear sus propias propiedades asociadas, consulte Información general sobre propiedades asociadas.

Las propiedades asociadas usan una sintaxis que se parece superficialmente a la sintaxis del elemento de propiedad, ya que también se especifica una combinación nombreDeTipo.nombreDePropiedad. Hay dos diferencias importantes:

  • Puede usar la combinación nombreDeTipo.nombreDePropiedad incluso cuando se establece una propiedad asociada mediante la sintaxis de atributo. Las propiedades asociadas son el único caso en el que calificar el nombre de propiedad es un requisito en una sintaxis de atributo.

  • También puede usar la sintaxis del elemento de propiedad para las propiedades asociadas. Sin embargo, para la sintaxis típica del elemento de propiedad, el nombreDeTipo que especifique es el elemento de objeto que contiene el elemento de propiedad. Si hace referencia a una propiedad asociada, nombreDeTipo es la clase que define la propiedad asociada, no el elemento de objeto contenedor.

Eventos adjuntos

Los eventos asociados son otro concepto de programación introducido en XAML donde los eventos se pueden definir mediante un tipo específico, pero los controladores se pueden asociar a cualquier elemento de objeto. En la implementación de WPF, a menudo el tipo que define un evento asociado es un tipo estático que define un servicio y, a veces, esos eventos asociados se exponen mediante un alias de evento enrutado en tipos que exponen el servicio. Los controladores de eventos asociados se especifican mediante la sintaxis de atributo. Al igual que con los eventos asociados, la sintaxis de atributo se expande con los eventos asociados para permitir un uso de nombreDeTipo.nombreDeEvento, donde nombreDeTipo es la clase que proporciona descriptores de acceso del controlador de eventos Add y Remove para la infraestructura de eventos asociada, y nombreDeEvento es el nombre del evento.

Anatomía de un elemento raíz XAML

En la tabla siguiente se muestra un elemento raíz XAML típico desglosado, en la que se muestran los atributos específicos de un elemento raíz:

Atributo Descripción
<Page Elemento de objeto de apertura del elemento raíz
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" El espacio de nombres XAML (WPF) predeterminado
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" El espacio de nombres XAML del lenguaje XAML
x:Class="ExampleNamespace.ExampleCode" Declaración de clase parcial que conecta el marcado a cualquier código subyacente definido para la clase parcial
> Fin del elemento de objeto de la raíz. El objeto aún no está cerrado porque el elemento contiene elementos secundarios

Usos de XAML opcionales y no recomendados

En las secciones siguientes se describen los usos de XAML que, técnicamente, son compatibles con procesadores XAML, pero que producen detalles u otros problemas estéticos que interfieren con el resto de archivos XAML legibles al desarrollar aplicaciones que contienen orígenes XAML.

Usos de elementos de propiedad opcionales

Entre los usos de elementos de propiedad opcionales se incluyen la escritura explícita de las propiedades de contenido de elementos que el procesador XAML considera implícitas. Por ejemplo, cuando declara el contenido de Menu, puede optar por declarar explícitamente la colección Items de Menu como una etiqueta de elemento de propiedad <Menu.Items> y colocar cada MenuItem dentro de <Menu.Items>, en lugar de usar el comportamiento implícito del procesador XAML que indica que todos los elementos secundarios de Menu deben ser MenuItem y se colocan en la colección Items. A veces, los usos opcionales pueden ayudar a aclarar visualmente la estructura de objetos como se representa en el marcado. O, a veces, un uso explícito de elementos de propiedad puede evitar el marcado que es técnicamente funcional pero visualmente confuso, como extensiones de marcado anidadas dentro de un valor de atributo.

Atributos cualificados completos nombreDeTipo.nombreDeMiembro

El formato de atributo nombreDeTipo.nombreDeMiembro funciona de forma más universal que solo el caso de evento enrutado. Pero en otras situaciones el formato es superfluo y debe evitarlo, aunque sea solo por motivos de estilo de marcado y legibilidad. En el ejemplo siguiente, cada una de las tres referencias al atributo Background son 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 la búsqueda calificada de esa propiedad en Button es correcta (Background se heredó de Control) y Button es la clase del elemento de objeto o una clase base. Control.Background funciona porque la clase Control define Background realmente y Control es una clase Button base.

Sin embargo, el siguiente ejemplo de formato nombreDeTipo.nombredeMiembro no funciona y, por tanto, se muestra como comentario:

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

Label es otra clase derivada de Control y, si hubiera especificado Label.Background dentro de un elemento de objeto Label, este uso habría funcionado. Sin embargo, dado que Label no es la clase o la clase base de Button, el comportamiento del procesador XAML especificado consiste en procesar Label.Background como una propiedad asociada. Label.Background no es una propiedad asociada disponible y se produce un error en este uso.

Elementos de propiedad nombreDeTipoBase.nombreDeMiembro

De forma análoga a cómo el formato nombreDeTipo.nombreDeMiembro funciona para la sintaxis de atributo, la sintaxis nombreDeTipoBase.nombreDeMiembro funciona para la sintaxis del elemento de propiedad. Por ejemplo, la sintaxis siguiente 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>

En este caso, el elemento de propiedad se ha dado como Control.Background aunque el elemento de propiedad estaba incluido en Button.

Pero al igual que el formato nombreDeTipo.nombreDeMiembro para atributos, nombreDeTipoBase.nombreDeMiembro es un estilo deficiente en el marcado y debe evitarlo.

Vea también