Share via


XAML y clases personalizadas

Actualización: noviembre 2007

Lenguaje de marcado de aplicaciones extensible (XAML) admite la capacidad para definir una clase o estructura personalizada en cualquier lenguaje de common language runtime (CLR) y, a continuación, tener acceso a esa clase utilizando marcado XAML, incluso utilizando una mezcla de etiquetas definidas en Windows Presentation Foundation (WPF)- XAML y de la clase personalizada XAML dentro del mismo archivo de marcado. En este tema se explican los requisitos que debe satisfacer una clase personalizada para ser utilizable como elemento XAML.

Este tema contiene las secciones siguientes.

  • Clases personalizadas en aplicaciones o ensamblados
  • Requisitos para una clase personalizada como elemento XAML
  • Requisitos para las propiedades de una clase personalizada como atributos XAML
  • Requisitos para la sintaxis de atributo del controlador de eventos XAML en los eventos de una clase personalizada
  • Escribir propiedades de colección
  • Declarar propiedades de contenido XAML
  • Serializar XAML
  • Temas relacionados

Clases personalizadas en aplicaciones o ensamblados

Las clases personalizadas que se utilizan en XAML se pueden definir de dos maneras distintas: dentro del código subyacente o de otro código que genere la aplicación Windows Presentation Foundation (WPF) primaria, o como una clase en un ensamblado independiente, tal como una aplicación ejecutable o una DLL utilizada como biblioteca de clases. Cada uno de estos enfoques tiene ventajas y desventajas particulares.

  • La ventaja de crear una biblioteca de clases es que cualquiera de esas clases personalizadas puede compartirse entre muchas posibles aplicaciones diferentes. Una biblioteca independiente también facilita las tareas de control de versión de las aplicaciones y simplifica la creación de una clase que se desee utilizar como elemento raíz en una página XAML.

  • La ventaja de definir las clases personalizadas en la aplicación es que esta técnica es relativamente ligera, y minimiza los problemas de implementación y pruebas que se encuentran al introducir ensamblados independientes además de la aplicación ejecutable principal. Sin embargo, una desventaja notable es que no se puede utilizar clases definidas en el mismo ensamblado como elemento raíz de una página XAML.

  • Ya estén definidas en el mismo ensamblado o en uno diferente, las clases personalizadas deben asignarse entre el espacio de nombres CLR y el espacio de nombres XML para utilizarse en XAML como elementos. Visite Espacios de nombres y asignación de espacios de nombres de XAML.

Requisitos para una clase personalizada como elemento XAML

Para permitir la creación de instancias como elementos de objeto, la clase debe cumplir los requisitos siguientes:

  • La clase personalizada debe ser pública y admitir un constructor público predeterminado (sin parámetros). (Las estructuras de código administrado admiten implícitamente este tipo de constructor.)

  • La clase personalizada no debe ser una clase anidada (las clases anidadas y el "punto" en su sintaxis interfieren con otras características de WPF tales como las propiedades asociadas).

Además de permitir la sintaxis de elemento de objeto, también debe habilitar la sintaxis de elemento de propiedad para cualquier otra propiedad pública que admita el objeto como su tipo de valor. Esto se debe a que ahora es posible crear instancias de un objeto como un elemento de objeto y a que el objeto puede rellenar el valor de elemento de propiedad de tales propiedades.

Estructuras

Las estructuras que se definen como tipos personalizados siempre se pueden construir en XAML en WPF. Esto se debe a que los compiladores de CLR crean implícitamente un constructor predeterminado para una estructura que inicializa todos los valores de propiedad a sus valores predeterminados. En algunos casos, no es deseable para una estructura el comportamiento predeterminado de construcción o de uso de elementos de objeto. Esto se puede deber a que la estructura está pensada para rellenar valores y funcionar, desde el punto de vista conceptual, como una unión, cuyos valores contenidos pueden tener interpretaciones mutuamente excluyentes, en cuyo caso ninguna de sus propiedades se podría establecer. Un ejemplo de WPF de este tipo de estructura es GridLength. En general, estas estructuras deben implementar un convertidor de tipos, de tal forma que los valores se puedan expresar en forma de atributos, mediante convenciones de cadena que creen las distintas interpretaciones o modos de los valores de la estructura; la estructura deberá también presentar un comportamiento parecido para la construcción de código mediante un constructor no predeterminado.

Requisitos para las propiedades de una clase personalizada como atributos XAML

Las propiedades deben hacer referencia a un tipo por valor (tal como un tipo primitivo) o utilizar una clase para tipo que tenga un constructor predeterminado o un convertidor de tipos dedicado en el nivel de clase.

Como alternativa, la propiedad puede hacer referencia a un tipo de clase abstracto o a una interfaz. Para las clases abstractas o las interfaces, la expectativa en tiempo de ejecución es que el valor de la propiedad deba rellenarse con instancias de clase prácticas que implementen la interfaz, o con instancias de clase que deriven de la clase abstracta.

Las propiedades se pueden declarar en una clase abstracta, pero únicamente se pueden establecer en clases prácticas derivadas de la clase abstracta, porque para crear el elemento de objeto para la clase exige que haya un constructor público predeterminado en la clase.

Sintaxis de atributo con convertidor de tipos

Si se proporciona un convertidor de tipos dedicado, con atributos, en el nivel de clase, la conversión de tipos aplicada habilita la sintaxis de atributo para cualquier propiedad que necesita crear instancias de ese tipo. Un convertidor de tipos no permite el uso de elemento de objeto del tipo; solamente la presencia de un constructor predeterminado para ese tipo habilita el uso de elemento de objeto. Por consiguiente, las propiedades habilitadas con convertidor de tipos, en general, no son utilizables en sintaxis de propiedad, a menos que el propio tipo admita también la sintaxis de elemento de objeto. La excepción consiste en que se puede especificar una sintaxis de elemento de propiedad, pero el elemento de propiedad debe contener una cadena. Ese uso es esencialmente el equivalente a un uso de sintaxis de atributo, realmente; este tipo de uso no es común a menos que se necesite una administración más sólida del espacio en blanco en el valor del atributo. Por ejemplo, lo siguiente es un uso de elemento de propiedad que toma una cadena y el uso de atributo equivalente:

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

Ejemplos de propiedades donde se permite la sintaxis de atributo, pero se rechaza la sintaxis de elemento de propiedad que contiene un elemento de objeto a través de XAML, son varias propiedades que toman el tipo Cursor. La clase Cursor tiene un objeto CursorConverter convertidor de tipos dedicado, pero no expone un constructor predeterminado, por lo que la propiedad Cursor solamente se puede establecer mediante sintaxis de atributo aunque el tipo Cursor real sea un tipo de referencia.

Convertidores de tipo por propiedad

La propia propiedad puede declarar también un convertidor de tipos en el nivel de propiedad. Esto habilita un "minilenguaje" que crea instancias de objetos del tipo de la propiedad en el propio código, procesando valores de cadena de entrada del atributo como entrada para una operación ConvertFrom basada en el tipo correspondiente. Normalmente, esto se hace para proporcionar un descriptor de acceso adecuado y no como único medio para habilitar la configuración de una propiedad en XAML. Sin embargo, también es posible utilizar convertidores de tipos para atributos cuando se desee utilizar tipos CLR que no proporcionen un constructor predeterminado ni un convertidor de tipos con atributos. Ejemplos de la API de WPF son ciertas propiedades que toman el tipo CultureInfo. En este caso, WPF utilizaba el tipo Microsoft .NET FrameworkCultureInfoexistente para resolver mejor la compatibilidad y los escenarios de migración utilizados en versiones anteriores de los marcos de trabajo, pero el tipo CultureInfo no admitía los constructores necesarios o la conversión de tipos de nivel de tipo para ser directamente utilizable como un valor de propiedad XAML.

Siempre que exponga una propiedad que tenga un uso XAML, en particular si está creando controles, debería considerar respaldar esa propiedad con una propiedad de dependencia. Esto es especialmente cierto si se utiliza la implementación Windows Presentation Foundation (WPF) existente del procesador de XAML, porque puede mejorar el rendimiento utilizando el respaldo con DependencyProperty. Una propiedad de dependencia expondrá características del sistema de propiedades para la propiedad de modo que los usuarios esperen una propiedad que permita el acceso mediante XAML. Esto incluye características tales como la animación, el enlace de datos y la compatibilidad con estilos. Para obtener más información, consulte Propiedades de dependencia personalizadas y Carga de XAML y propiedades de dependencia.

Escribir y asignar atributos a un convertidor de tipos

Con frecuencia, necesitará escribir una clase personalizada derivada de TypeConverter para proporcionar conversión de tipos a un tipo de propiedad. Para obtener instrucciones sobre cómo derivar y crear un convertidor de tipos que admita usos XAML y cómo aplicar el objeto TypeConverterAttribute, vea Clases TypeConverter y XAML.

Requisitos para la sintaxis de atributo del controlador de eventos XAML en los eventos de una clase personalizada

Para ser utilizable como un evento CLR, el evento se debe exponer como un evento público en una clase que admita un constructor predeterminado o en una clase abstracta donde se pueda tener acceso al evento en clases derivadas. Para poder utilizarse cómodamente como un evento enrutado, el evento de CLR debe implementar métodos add y remove explícitos que agreguen y quiten controladores para la firma de evento CLR y reenvíen esos controladores a los métodos AddHandler y RemoveHandler. Estos métodos agregan o quitan controladores del almacén del controlador de eventos enrutados en la instancia a la que está asociado el evento.

Nota

Es posible registrar controladores directamente para eventos enrutados utilizando AddHandler, así como no definir deliberadamente un evento CLR que exponga el evento enrutado. En general, esto no es recomendable, porque el evento no habilitará la sintaxis de atributo XAML para asociar controladores y la clase resultante ofrecerá una vista XAML menos transparente del modelo de objetos de clase.

Escribir propiedades de colección

Las propiedades que toman un tipo de colección tienen una sintaxis XAML que permite especificar objetos que se agregan a la colección. Esta sintaxis tiene dos características notables.

  • El objeto que es el objeto de colección no necesita especificarse en la sintaxis de elemento de objeto. La presencia de ese tipo de colección es implícita siempre que se especifique una propiedad de XAML que tome un tipo de colección.

  • Los elementos secundarios de la propiedad de colección se procesan para convertirse en miembros de la colección. Normalmente, el acceso del código a los miembros de una colección se realiza a través de métodos de colección, tales como Add o mediante una propiedad indizadora de la colección. Sin embargo, la sintaxis XAML no admite métodos ni indizadores. Las colecciones son obviamente un requisito muy común para generar un árbol de elementos y se necesita alguna manera de rellenarlas en XAML declarativo. Por consiguiente, los elementos secundarios de una propiedad de colección se procesan agregándolos a la colección que es el valor de tipo de la propiedad de colección.

El procesador WPFXAML utiliza la definición siguiente para lo que constituye una propiedad de colección. El tipo de propiedad de la propiedad debe implementar una de las opciones siguientes:

Cada uno de estos tipos tiene un método Add, que es utilizado por el procesador de impresión XAML para agregar elementos a la colección subyacente.

Nota

Las interfaces de List y Dictionary genéricas (IList<T> y IDictionary<TKey, TValue>) no se admiten para la detección de colecciones por parte del procesador de XAML de WPF. Sin embargo, puede utilizar List<T> como una clase base, ya que implementa directamente IList o Dictionary<TKey, TValue>, ya que ésta implementa directamente IDictionary.

Al declarar una propiedad que toma una colección, tenga cuidado con el modo en el que se inicializa ese valor de propiedad en las nuevas instancias del tipo. Si no está implementando la propiedad como una propiedad de dependencia, es aconsejable hacer que la propiedad utilice un campo de respaldo que llame al constructor del tipo de colección. Si la propiedad es una propiedad de dependencia, quizá necesite inicializar la propiedad de colección como parte del constructor de tipo predeterminado. Esto se debe a que una propiedad de dependencia toma su valor predeterminado de los metadatos y, habitualmente, no se desea que el valor inicial de una propiedad de colección sea una colección estática y compartida (debe haber una instancia de colección por cada instancia del tipo contenedor). Para obtener más información, consulte Propiedades de dependencia personalizadas.

Puede implementar un tipo de colección personalizado para la propiedad de colección. Debido al tratamiento de propiedad de colección implícito, no es necesario que el tipo de colección personalizado proporcione un constructor predeterminado utilizar implícitamente el tipo en XAML. Sin embargo, puede proporcionar un constructor predeterminado para el tipo de colección. Puede que valga la pena hacerlo así porque, a menos que proporcione un constructor predeterminado, no podrá declarar explícitamente la colección como un elemento de objeto. Es posible que algunos autores de marcado prefieran considerar la colección explícita como una cuestión de estilo de marcado. Además, un constructor predeterminado puede simplificar los requisitos de inicialización al crear nuevos objetos que utilicen el tipo de colección como un valor de propiedad.

Declarar propiedades de contenido XAML

El lenguaje XAML define el concepto de una propiedad de contenido XAML. Cada clase utilizable en sintaxis de objeto puede tener exactamente una propiedad de contenido XAML. Para declarar una propiedad para que sea la propiedad de contenido XAML para la clase, aplique ContentPropertyAttribute como parte de la definición de clase. Especifique el nombre de la propiedad de contenido XAML que desee como Name en el atributo.

Puede especificar una propiedad de colección como propiedad de contenido XAML. El resultado es un uso para esa propiedad mediante la cual el elemento de objeto puede tener uno o más elementos secundarios, sin elementos de objeto de colección intermedios ni etiquetas de elemento de propiedad. Estos elementos se tratan entonces como el valor para la propiedad de contenido XAML y se agregan a la instancia de respaldo de la colección.

Algunas propiedades XAML de WPF existentes utilizan el tipo de propiedad de Object. Esto permite que una propiedad de contenido XAML pueda tomar valores primitivos tales como String así como un valor de objeto de referencia único. Si sigue este modelo, el tipo será responsable de la determinación de tipo, así como del control de los tipos posibles. La razón típica para un modelo de tipo Object es admitir tanto un medio simple para agregar contenido de objetos en forma de cadena (que recibe un tratamiento de presentación predeterminado) como un medio avanzado de agregar contenido de objetos que especifique una presentación no predeterminada.

Serializar XAML

Para determinados escenarios, tales como la creación de controles, quizá desee asegurarse de que toda representación de objetos para la que se pueda crear instancias en XAML pueda serializarse también en XAML equivalente. Los requisitos de serialización no se describen en este tema. Vea Información general sobre la creación de controles y Árbol de elementos y serialización.

Vea también

Conceptos

Información general sobre XAML

Propiedades de dependencia personalizadas

Información general sobre la creación de controles

Información general sobre elementos base

Carga de XAML y propiedades de dependencia