Compartir a través de


Extensiones de marcado y WPF XAML

En este tema se presenta el concepto de extensiones de marcado para XAML, incluidas sus reglas de sintaxis, propósito y el modelo de objetos de clase que los subyace. Las extensiones de marcado son una característica general del lenguaje XAML y de la implementación de .NET de los servicios XAML. En este tema se detallan específicamente las extensiones de marcado para su uso en XAML de WPF.

Procesadores XAML y extensiones de marcado

Por lo general, un analizador XAML puede interpretar un valor de atributo como una cadena literal que se puede convertir en un primitivo o convertirlo en un objeto por algún medio. Uno de estos medios es haciendo referencia a un convertidor de tipos; esto se documenta en el tema TypeConverters y XAML. Sin embargo, hay escenarios en los que se requiere un comportamiento diferente. Por ejemplo, se puede indicar a un procesador XAML que un valor de un atributo no debe dar lugar a un nuevo objeto en el gráfico de objetos. En su lugar, el atributo debe dar lugar a un gráfico de objetos que haga referencia a un objeto ya construido en otra parte del gráfico o en un objeto estático. Otro escenario es que se puede indicar a un procesador XAML que use una sintaxis que proporcione argumentos no predeterminados al constructor de un objeto. Estos son los tipos de escenarios en los que una extensión de marcado puede proporcionar la solución.

Sintaxis básica de la extensión de marcado

Se puede implementar una extensión de marcado para proporcionar valores para las propiedades en un uso como atributo, propiedades en un uso como elemento de propiedad o ambos.

Cuando se usa para proporcionar un valor de atributo, la sintaxis que distingue una secuencia de extensión de marcado a un procesador XAML es la presencia de llaves de apertura y cierre ({ y }). El tipo de extensión de marcado se identifica a través del token de cadena que está inmediatamente después de la llave de apertura.

Cuando se usa en la sintaxis del elemento de propiedad, una extensión de marcado es visualmente la misma que cualquier otro elemento usado para proporcionar un valor de elemento de propiedad: una declaración de elemento XAML que hace referencia a la clase de extensión de marcado como un elemento, entre corchetes angulares (<>).

XAML-Defined Extensiones de marcado

Existen varias extensiones de marcado que no son específicas de la implementación de WPF de XAML, sino que son implementaciones de intrínsecos o características de XAML como lenguaje. Estas extensiones de marcado se implementan en el ensamblado System.Xaml como parte de los servicios XAML generales de .NET Framework y están dentro del espacio de nombres XAML del lenguaje XAML. En términos de uso común de marcado, estas extensiones de marcado suelen ser identificables por el prefijo x: en su uso. La MarkupExtension clase base (también definida en System.Xaml) proporciona el patrón que deben seguir todas las extensiones de marcado para ser compatibles con los lectores y escritores de XAML, incluyendo los de XAML en WPF.

  • x:Type proporciona el Type objeto para el tipo con nombre. Esta instalación se usa con más frecuencia en estilos y plantillas. Para obtener más información, consulte extensión de marcado x:Type.

  • x:Static genera valores estáticos. Los valores proceden de entidades de código de tipo valor que no son directamente el tipo del valor de una propiedad de destino, pero que se pueden evaluar con ese tipo. Para obtener más información, consulte Extensión de marcado x:Static.

  • x:Null especifica null como un valor para una propiedad y se puede usar para atributos o valores de elemento de propiedad. Para obtener más información, consulte extensión de marcado x:Null.

  • x:Array proporciona compatibilidad para la creación de matrices generales en la sintaxis XAML, en los casos en los que la compatibilidad de recopilación proporcionada por los elementos base y los modelos de control de WPF no se usa deliberadamente. Para obtener más información, consulte extensión de marcado x:Array.

Nota:

El prefijo x: se usa para el mapeo típico del espacio de nombres de los intrínsecos del lenguaje XAML en el elemento raíz de un archivo XAML o en una implementación. Por ejemplo, las plantillas de Visual Studio para aplicaciones WPF inician un archivo XAML usando esta x: asignación. Puedes elegir un token de prefijo diferente en tu propia asignación de espacio de nombres XAML, pero esta documentación asume la asignación predeterminada x: como medio para identificar esas entidades que son una parte definida del espacio de nombres XAML para el lenguaje XAML, en lugar del espacio de nombres predeterminado de WPF u otros espacios de nombres XAML no relacionados con un marco específico.

WPF-Specific Extensiones de Marcado

Las extensiones de marcado más comunes que se usan en la programación de WPF son las que admiten referencias de recursos (StaticResource y DynamicResource) y las que admiten el enlace de datos (Binding).

  • StaticResource proporciona un valor para una propiedad sustituyendo el valor de un recurso ya definido. Finalmente, una StaticResource evaluación se realiza en el tiempo de carga XAML y no tiene acceso al grafo de objetos durante el tiempo de ejecución. Para obtener más información, consulte Extensión de marcado StaticResource.

  • DynamicResource proporciona un valor para una propiedad aplazando ese valor para que sea una referencia en tiempo de ejecución a un recurso. Una referencia de recursos dinámicos fuerza una nueva consulta cada vez que se accede a dicho recurso y al tener acceso al gráfico de objetos en tiempo de ejecución. Para obtener este acceso, el concepto de DynamicResource es respaldado por las propiedades de dependencia en el sistema de propiedades de WPF y por las expresiones evaluadas. Por lo tanto, solo puedes utilizar DynamicResource como destino para una propiedad de dependencia. Para obtener más información, consulte Extensión de marcado DynamicResource.

  • Binding proporciona un valor enlazado a datos para una propiedad mediante el contexto de datos que se aplica al objeto primario en tiempo de ejecución. Esta extensión de marcado es relativamente compleja, ya que permite una sintaxis sustancial en línea para especificar un enlace de datos. Para obtener más información, consulte Extensión de marcado de vinculación.

  • RelativeSource proporciona información de origen para un Binding objeto que puede navegar por varias relaciones posibles en el árbol de objetos en tiempo de ejecución. Esto proporciona fuentes especializadas para enlaces creados en plantillas de uso múltiple o creados en código sin conocimiento completo del árbol de objetos circundante. Para obtener más información, consulte RelativeSource MarkupExtension.

  • TemplateBinding permite que una plantilla de control use valores para las propiedades con plantilla que proceden de propiedades definidas por el modelo de objetos de la clase que usará la plantilla. Es decir, la propiedad dentro de la definición de plantilla puede tener acceso a un contexto que solo existe una vez aplicada la plantilla. Para obtener más información, consulte la extensión de marcado TemplateBinding. Para obtener más información sobre el uso práctico de TemplateBinding, vea Aplicación de estilos con controlTemplates Sample.

  • ColorConvertedBitmap admite un escenario de creación de imágenes relativamente avanzado. Para obtener más información, consulte Extensión de marcado ColorConvertedBitmap.

  • ComponentResourceKey y ThemeDictionary admiten aspectos de la búsqueda de recursos, especialmente para recursos y temas que se empaquetan con controles personalizados. Para obtener más información, vea ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension o Control Authoring Overview.

*Cursos de extensión

Para el lenguaje XAML general y las extensiones de marcado específicas de WPF, el comportamiento de cada extensión de marcado se identifica a un procesador XAML a través de una clase *Extension que deriva de MarkupExtension y proporciona una implementación del método ProvideValue. Este método en cada extensión proporciona el objeto que se devuelve cuando se evalúa la extensión de marcado. El objeto devuelto se evalúa normalmente en función de los distintos tokens de cadena que se pasan a la extensión de marcado.

Por ejemplo, la StaticResourceExtension clase proporciona la implementación básica de la búsqueda de recursos real para que su ProvideValue implementación devuelva el objeto solicitado, utilizando como entrada una cadena específica que se emplea para buscar el recurso por su x:Key. Gran parte de este detalle de implementación no es importante si usa una extensión de marcado existente.

Algunas extensiones de marcado no usan argumentos de token de cadena. Esto se debe a que devuelven un valor estático o coherente, o porque el contexto del valor que se debe devolver está disponible a través de uno de los servicios que se pasan a través del serviceProvider parámetro .

El *Extension patrón de nomenclatura es para mayor comodidad y coherencia. No es necesario que un procesador XAML tenga que identificar esa clase como apoyo para una extensión de marcado. Siempre que el código base incluya System.Xaml y use implementaciones de servicios XAML de .NET Framework, todo lo que es necesario para reconocerse como una extensión de marcado XAML es derivar de MarkupExtension y admitir una sintaxis de construcción. WPF define las clases de habilitación de extensiones de marcado que no siguen el *Extension patrón de nomenclatura, por ejemplo Binding. Normalmente, la razón de esto es que la clase admite escenarios más allá de la compatibilidad con la extensión de marcado puro. En el caso de Binding, esa clase admite el acceso en tiempo de ejecución a los métodos y propiedades del objeto para escenarios que no tienen nada que ver con XAML.

Interpretación de clase de extensión del texto de inicialización

Los tokens de cadena que aparecen después del nombre de la extensión de marcado y que permanecen dentro de las llaves se interpretan mediante un procesador XAML de una de las siguientes maneras:

  • Una coma siempre representa el separador o delimitador de tokens individuales.

  • Si los tokens separados individuales no contienen signos iguales, cada token se trata como argumento de constructor. Cada parámetro de constructor debe proporcionarse como el tipo esperado por esa firma y en el orden adecuado esperado por esa firma.

    Nota:

    Un procesador XAML debe llamar al constructor que coincide con el recuento de argumentos del número de pares. Por este motivo, si va a implementar una extensión de marcado personalizada, no proporcione varios constructores con el mismo recuento de argumentos. El comportamiento de un procesador XAML no está definido si existe más de una ruta de acceso del constructor de extensión de marcado con el mismo número de parámetros, pero debe prever que se permite que un procesador XAML lance una excepción durante el uso si esta situación existe en las definiciones de tipos de extensiones de marcado.

  • Si los tokens separados individuales contienen signos iguales, un procesador XAML llama primero al constructor sin parámetros para la extensión de marcado. A continuación, cada par nombre=valor se interpreta como un nombre de propiedad que existe en la extensión de marcado y un valor para asignar a esa propiedad.

  • Si hay un resultado paralelo entre el comportamiento del constructor y el comportamiento de configuración de propiedades en una extensión de marcado, no importa qué comportamiento se use. Es más común usar los pares de propiedad=valor para las extensiones de marcado que tienen más de una propiedad configurable, aunque solo sea porque hace que tu marcado sea más intencional y reduces la probabilidad de transponer accidentalmente los parámetros del constructor. (Cuando se especifican pares property=value, esas propiedades pueden estar en cualquier orden). Además, no hay ninguna garantía de que una extensión de marcado proporciona un parámetro de constructor que establece cada una de sus propiedades que se pueden establecer. Por ejemplo, Binding es una extensión de marcado, con muchas propiedades que se pueden establecer a través de la extensión en formatode valor de =, pero Binding solo admite dos constructores: un constructor sin parámetros y otro que establece una ruta de acceso inicial.

  • No se puede pasar una coma literal a una extensión de marcado sin escape.

Secuencias de escape y extensiones de marcado

El control de atributos en un procesador XAML usa las llaves como indicadores de una secuencia de extensión de marcado. También es posible generar un valor de atributo de carácter de llave literal si es necesario, escribiendo una secuencia de escape mediante un par de llaves vacías seguido de la llave literal. Consulte {} Secuencia de escape: extensión de marcado.

Anidar extensiones de marcado en el uso de XAML

Se admite el anidamiento de varias extensiones de marcado y cada extensión de marcado se evaluará primero más profundamente. Por ejemplo, considere el uso siguiente:

<Setter Property="Background"
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

En este uso, la x:Static instrucción se evalúa primero y devuelve una cadena. A continuación, esa cadena se usa como argumento para DynamicResource.

Extensiones de marcado y sintaxis de elementos de propiedad

Cuando se usa como elemento de objeto que rellena el valor de un elemento de propiedad, una clase de extensión de marcado no se diferencia visualmente de un elemento de objeto respaldado por un tipo típico que se puede usar en XAML. La diferencia práctica entre un elemento de objeto típico y una extensión de marcado es que la extensión de marcado se evalúa en un valor tipado o se pospone como expresión. Por lo tanto, los mecanismos para los posibles errores de tipo de los valores de propiedad de la extensión de marcado serán diferentes, de forma similar a cómo se trata una propiedad enlazada en tiempo de ejecución en otros modelos de programación. Un elemento de objeto normal se evaluará para verificar si el tipo coincide con la propiedad de destino que se está configurando cuando se analiza el XAML.

La mayoría de las extensiones de marcado, cuando se utilizan en la sintaxis del elemento de objeto para rellenar un elemento de propiedad, no tendrían contenido ni ninguna sintaxis adicional de elemento de propiedad dentro. Por lo tanto, cerraría la etiqueta del elemento de objeto y no proporcionaría ningún elemento secundario. Siempre que un procesador XAML encuentre cualquier elemento de objeto, se llama al constructor de esa clase, que crea una instancia del objeto creado a partir del elemento analizado. Una clase de extensión de marcado no es diferente: si quiere que la extensión de marcado se pueda usar en la sintaxis del elemento de objeto, debe proporcionar un constructor sin parámetros. Algunas extensiones de marcado existentes tienen al menos un valor de propiedad necesario que se debe especificar para la inicialización efectiva. Si es así, ese valor de propiedad se suele dar como un atributo de propiedad en el elemento object. En las páginas de referencia Características del lenguaje XAML (x:) y Extensiones XAML de WPF, se indicarán las extensiones de marcado que tienen propiedades necesarias (y los nombres de las propiedades necesarias). Las páginas de referencia también observarán si no se permite la sintaxis de elemento de objeto o la sintaxis de atributo para extensiones de marcado concretas. Un caso notable es la extensión de marcado x:Array, que no puede admitir la sintaxis de atributo porque el contenido de esa matriz debe especificarse dentro del etiquetado como contenido. El contenido de la matriz se controla como objetos generales, por lo que no es factible ningún convertidor de tipos predeterminado para el atributo. Además, la extensión de marcado x:Array requiere un type parámetro .

Consulte también