Compartir a través de


Definición de tipos personalizados para su uso con servicios XAML de .NET

Al definir tipos personalizados que son objetos de negocio o que no tienen una dependencia en marcos específicos, hay ciertos procedimientos recomendados para XAML que puedes seguir. Si sigues estos procedimientos, los servicios XAML de .NET y sus lectores XAML y escritores XAML pueden detectar las características XAML de tu tipo y darle una representación adecuada en un flujo de nodo XAML mediante el sistema de tipos XAML. En este tema se describen los procedimientos recomendados para las definiciones de tipos, las definiciones de miembro y la asignación clR de tipos o miembros.

Patrones de constructor y definiciones de tipos para XAML

Para crear instancias como un elemento de objeto en XAML, una clase personalizada debe cumplir los siguientes requisitos:

  • La clase personalizada debe ser pública y debe exponer un constructor público sin parámetros. (Consulte la sección siguiente para obtener notas sobre las estructuras).

  • La clase personalizada no debe ser una clase anidada. El "punto" adicional en la ruta de acceso de nombre completo hace que la división del espacio de nombres de clase sea ambigua e interfiera con otras características XAML, como las propiedades adjuntas. Si se puede crear una instancia de un objeto como elemento de objeto, el objeto creado puede rellenar el formulario de elemento de propiedad de cualquier propiedad que tome el objeto como su tipo subyacente.

Todavía puede proporcionar valores de objeto para los tipos que no cumplen estos criterios si habilita un convertidor de valores. Para obtener más información, consulta convertidores de tipos y extensiones de marcado para xaml.

Estructuras

Las estructuras siempre se pueden construir en XAML mediante la definición de CLR. Esto se debe a que un compilador CLR crea implícitamente un constructor sin parámetros para una estructura. Este constructor inicializa todos los valores de propiedad en sus valores predeterminados.

En algunos casos, el comportamiento de construcción predeterminado para una estructura no es deseable. Esto puede deberse a que la estructura está pensada para rellenar valores y funcionar conceptualmente como una unión. Como unión, los valores contenidos pueden tener interpretaciones mutuamente excluyentes y, por lo tanto, ninguna de sus propiedades se puede establecer. Un ejemplo de esta estructura en el vocabulario de WPF es GridLength. Estas estructuras deben implementar un convertidor de tipos para que los valores se puedan expresar en forma de atributo, mediante convenciones de cadena que crean las diferentes interpretaciones o modos de los valores de estructura. La estructura también debe exponer un comportamiento similar para la construcción de código a través de un constructor sin parámetros.

Interfaces

Las interfaces se pueden usar como tipos subyacentes de miembros. El sistema de tipos XAML comprueba la lista asignable y espera que el objeto proporcionado como valor se pueda asignar a la interfaz. No hay ningún concepto de cómo se debe presentar la interfaz como un tipo XAML siempre que un tipo asignable relevante admita los requisitos de construcción xaml.

Métodos de fábrica

Los métodos de fábrica son una característica XAML 2009. Modifican el principio XAML de que los objetos deben tener constructores sin parámetros. Los métodos de fábrica no se documentan en este artículo. Consulte directiva x:FactoryMethod.

Enumeraciones

Las enumeraciones tienen un comportamiento de conversión de tipos nativos xaml. Los nombres de constantes de enumeración especificados en XAML se resuelven con el tipo de enumeración subyacente y devuelven el valor de enumeración a un escritor de objetos XAML.

XAML admite un uso de estilo de marcas para enumeraciones con FlagsAttribute aplicados. Para obtener más información, consulta sintaxis XAML en detalle. (sintaxis XAML en detalle se escribe para la audiencia de WPF, pero la mayoría de la información de ese tema es relevante para XAML que no es específico de un marco de implementación determinado).

Definiciones de miembros

Los tipos pueden definir miembros para el uso de XAML. Es posible que los tipos definan miembros que se pueden usar xaml aunque ese tipo específico no se pueda usar en XAML. Esto es posible debido a la herencia clR. Siempre que algún tipo que hereda el miembro admita el uso de XAML como un tipo, y el miembro admite el uso de XAML para su tipo subyacente o tiene disponible una sintaxis XAML nativa, ese miembro es utilizable en XAML.

Propiedades

Si defines propiedades como una propiedad CLR pública mediante el típico get CLR y set patrones de descriptor de acceso y palabras clave apropiadas para el lenguaje, el sistema de tipos XAML puede notificar la propiedad como miembro con la información adecuada proporcionada para las propiedades de XamlMember, como IsReadPublic y IsWritePublic.

Las propiedades específicas pueden habilitar una sintaxis de texto aplicando TypeConverterAttribute. Para obtener más información, consulta convertidores de tipos y extensiones de marcado para xaml.

En ausencia de una sintaxis de texto o una conversión XAML nativa y, en ausencia de un direccionamiento indirecto adicional, como un uso de extensión de marcado, el tipo de una propiedad (TargetType en el sistema de tipos XAML) debe poder devolver una instancia a un escritor de objetos XAML tratando el tipo de destino como un tipo CLR.

Si usa XAML 2009, extensión de marcado x:Reference se puede usar para proporcionar valores si no se cumplen las consideraciones anteriores; sin embargo, es más un problema de uso que un problema de definición de tipo.

Eventos

Si defines eventos como un evento CLR público, el sistema de tipos XAML puede notificar el evento como miembro con IsEvent como true. El cableado de los controladores de eventos no está dentro del ámbito de las funcionalidades de servicios XAML de .NET; el cableado queda a marcos e implementaciones específicos.

Métodos

El código insertado para los métodos no es una funcionalidad XAML predeterminada. En la mayoría de los casos, no haces referencia directamente a miembros de métodos de XAML y el rol de métodos en XAML es solo para proporcionar compatibilidad con patrones XAML específicos. directiva x:FactoryMethod es una excepción.

Campos

Las directrices de diseño clR desaconsejan los campos no estáticos. En el caso de los campos estáticos, solo puede acceder a los valores de campo estáticos a través de extensión de marcado estático; en este caso, no está haciendo nada especial en la definición clR para exponer un campo para usos de estáticos.

Miembros adjuntables

Los miembros adjuntables se exponen a XAML a través de un patrón de método de descriptor de acceso en un tipo de definición. El tipo de definición en sí no tiene que usarse como un objeto XAML. De hecho, un patrón común es declarar una clase de servicio cuyo rol sea propietario del miembro adjuntable e implementar los comportamientos relacionados, pero no sirva ninguna otra función, como una representación de la interfaz de usuario. Para las secciones siguientes, el marcador de posición PropertyName representa el nombre del miembro adjuntable. Ese nombre debe ser válido en el Gramática xamlName.

Tenga cuidado con las colisiones de nombres entre estos patrones y otros métodos de un tipo. Si existe un miembro que coincide con uno de los patrones, se puede interpretar como una ruta de uso de miembros adjuntable por un procesador XAML incluso si no era tu intención.

Descriptor de acceso GetPropertyName

La firma del descriptor de acceso GetPropertyName debe ser:

public static object GetPropertyName(object target)

  • El objeto target se puede especificar como un tipo más específico en la implementación. Puede usarlo para definir el ámbito del uso de su miembro adjuntable; los usos fuera del ámbito previsto producirán excepciones de conversión no válidas que, a continuación, se muestran mediante un error de análisis xaml. El nombre del parámetro target no es un requisito, pero se denomina target por convención en la mayoría de las implementaciones.

  • El valor devuelto se puede especificar como un tipo más específico en la implementación.

Para admitir una sintaxis de texto habilitada TypeConverter para el uso de atributos del miembro adjuntable, aplique TypeConverterAttribute al descriptor de acceso GetPropertyName. La aplicación a la get en lugar del set puede parecer no intuitiva; Sin embargo, esta convención puede admitir el concepto de miembros adjuntables de solo lectura que son serializables, lo que resulta útil en escenarios de diseñador.

Descriptor de acceso SetPropertyName

La firma del descriptor de acceso SetPropertyName debe ser:

public static void SetPropertyName(object target, object value)

  • El objeto target se puede especificar como un tipo más específico en la implementación, con la misma lógica y consecuencias que se describe en la sección anterior.

  • El objeto value se puede especificar como un tipo más específico en la implementación.

Recuerde que el valor de este método es la entrada procedente del uso de XAML, normalmente en forma de atributo. Desde el formulario de atributo debe haber compatibilidad con el convertidor de valores para una sintaxis de texto y el atributo en el descriptor de acceso de GetPropertyNames.

Almacenes de miembros adjuntables

Normalmente, los métodos de descriptor de acceso no son suficientes para proporcionar un medio para colocar valores de miembro adjuntables en un gráfico de objetos, o para recuperar valores del gráfico de objetos y serializarlos correctamente. Para proporcionar esta funcionalidad, los objetos target de las firmas de descriptor de acceso anteriores deben ser capaces de almacenar valores. El mecanismo de almacenamiento debe ser coherente con el principio de miembro adjuntable que el miembro se puede adjuntar a destinos en los que el miembro adjuntable no está en la lista de miembros. Los servicios XAML de .NET proporcionan una técnica de implementación para los almacenes de miembros adjuntables a través de las API IAttachedPropertyStore y AttachablePropertyServices. los escritores XAML usan IAttachedPropertyStore para detectar la implementación de la tienda y deben implementarse en el tipo que es el target de los descriptores de acceso. Las API de AttachablePropertyServices estáticas se usan en el cuerpo de los descriptores de acceso y hacen referencia al miembro adjuntable por su AttachableMemberIdentifier.

La asignación correcta de los tipos, miembros y ensamblados es importante para informar de la información del sistema de tipos XAML a los servicios XAML de .NET. La información del sistema de tipos XAML de informes es relevante si se aplica alguna de las situaciones siguientes:

  • Tienes intención de usar tus tipos con sistemas XAML que se basan directamente en lectores XAML de servicios XAML de .NET y escritores XAML.
  • Defines o usas un marco de trabajo que se basa en esos lectores XAML y escritores XAML.

Para obtener una lista de cada atributo relacionado con XAML que sea relevante para la compatibilidad con XAML de los tipos personalizados, consulta XAML-Related atributos CLR para tipos y bibliotecas personalizados.

Uso

El uso de tipos personalizados requiere que el autor de marcado asigne un prefijo para el ensamblado y el espacio de nombres CLR que contengan el tipo personalizado. Este procedimiento no está documentado en este tema.

Nivel de entrada

XAML proporciona un medio para cargar y crear instancias de tipos que tienen un nivel de acceso internal. Esta funcionalidad se proporciona para que el código de usuario pueda definir sus propios tipos y, a continuación, crear instancias de esas clases desde el marcado que también forma parte del mismo ámbito de código de usuario.

Un ejemplo de WPF es cada vez que el código de usuario define un UserControl que está pensado como una manera de refactorizar un comportamiento de interfaz de usuario, pero no como parte de ningún mecanismo de extensión posible que pueda estar implícito declarando la clase auxiliar con public nivel de acceso. Este UserControl se puede declarar con internal acceso si el código de respaldo se compila en el mismo ensamblado desde el que se hace referencia a él como un tipo XAML.

Para una aplicación que carga XAML bajo plena confianza y usa XamlObjectWriter, la carga de clases con internal nivel de acceso siempre está habilitada.

Para una aplicación que carga XAML bajo confianza parcial, puedes controlar las características de nivel de acceso mediante la API de XamlAccessLevel. Además, los mecanismos de aplazamiento (como el sistema de plantillas de WPF) deben poder propagar los permisos de nivel de acceso y conservarlos para las evaluaciones en tiempo de ejecución finales; esto se controla internamente pasando la información de XamlAccessLevel.

Implementación de WPF

WPF XAML usa un modelo de acceso de confianza parcial donde si BAML se carga bajo confianza parcial, el acceso está restringido a AssemblyAccessTo para el ensamblado que es el origen baml. Para el aplazamiento, WPF usa IXamlObjectWriterFactory.GetParentSettings como mecanismo para pasar la información de nivel de acceso.

En la terminología XAML de WPF, un tipo interno es un tipo definido por el mismo ensamblado que también incluye el XAML que hace referencia. Este tipo se puede asignar a través de un espacio de nombres XAML que omite deliberadamente la parte assembly= de una asignación, por ejemplo, xmlns:local="clr-namespace:WPFApplication1". Si BAML hace referencia a un tipo interno y ese tipo tiene internal nivel de acceso, esto genera una clase GeneratedInternalTypeHelper para el ensamblado. Si desea evitar GeneratedInternalTypeHelper, debe usar public nivel de acceso o debe factorizar la clase pertinente en un ensamblado independiente y hacer que ese ensamblado dependa.

Consulte también