Almacén de metadatos
Actualización: noviembre 2007
El marco de Windows Presentation Foundation (WPF) Designer for Visual Studio desacopla los metadatos en tiempo de diseño de la implementación. Separar los metadatos del código en tiempo de ejecución es un importante principio de diseño por las razones siguientes.
Generar respuestas y logísticas de integración entre equipos pueden hacer que la compilación de metadatos en el código del marco resulte tedioso.
Si se compilan los metadatos en el código en tiempo de ejecución, se evita que las herramientas externas, como WPF Designer o Expression Blend, modifiquen esos metadatos más adelante. Se trata de una cuestión clave en lo que se refiere a agilidad. Si no se desacoplan los metadatos en tiempo de diseño del código,Visual Studio no pueden controlar las versiones de sus diseñadores sin requerir una nueva versión de .NET Framework.
Compilar los metadatos en tiempo de ejecución aumenta significativamente el tamaño del ensamblado en tiempo de ejecución. Los atributos de tiempo de diseño también ralentizan el motor en tiempo de ejecución. Las características del motor en tiempo de ejecución, como el enlace de datos, que utiliza la reflexión, se ven afectadas cuando en la memoria se cargan atributos adicionales.
Los metadatos en tiempo de diseño aportan la “personalidad” del diseñador. Las características de un diseñador están en gran medida vinculadas a la aplicación que las hospeda y no al motor en tiempo de ejecución. WPF Designer y Expression Blend usan conjuntos diferentes de metadatos para proporcionar un conjunto de características que se destinan para un tipo específico de usuario.
El almacén de metadatos
El almacén de metadatos es una ubicación de almacenamiento para los metadatos en tiempo de diseño. La API del almacén de metadatos es simple. Las tablas de atributos de metadatos se agregan llamando al método AddAttributeTable. Cuando una tabla se agrega al almacén de metadatos, los atributos definidos estarán disponibles en las consultas TypeDescriptor. Si ya se ha consultado un tipo y la tabla contiene atributos adicionales para este tipo, se provoca un evento Refreshed para informar de que los metadatos del tipo han cambiado.
La tabla de atributos
Una tabla de atributos es esencialmente un diccionario de sólo lectura, pero las claves y valores se calculan por separado. Resulta eficaz realizar consultas en una tabla de atributos si contiene atributos para un tipo determinado. El conjunto real de atributos se crea a petición. Se llama al método GetCustomAttributes para recuperar los metadatos personalizados para un tipo determinado.
Una tabla de atributos admite únicamente las propiedades de un tipo. Una tabla de atributos no admite atributos en campos o métodos.
El generador de la tabla de atributos
Para crear una tabla de atributos, empiece creando una instancia de la clase AttributeTableBuilder. Los metadatos se agregan al generador de la tabla de atributos llamando a las sobrecargas AddCustomAttributes. Cuando termine de agregar metadatos, genere una tabla de atributos desde el generador de la tabla de atributos llamando al método CreateTable. Los métodos del generador de la tabla de atributos admiten delegados de devolución de llamada, por tanto, la creación de la tabla de atributos se puede aplazar hasta que sea necesario.
Creación de atributos personalizados
El almacén de metadatos se basa en el hecho de que los atributos personalizados tengan una invalidación correctamente definida para su propiedad TypeId. El almacén de metadatos utiliza la propiedad TypeId para determinar si dos atributos del mismo tipo o de un tipo diferente se deben tratar como las mismas instancias.
La clase base Attribute define la propiedad TypeId de la siguiente manera.
public class Attribute
{
...
public virtual object TypeId
{
get
{
return base.GetType();
}
}
...
}
Esta implementación hace que dos instancias del mismo tipo Attribute aparezcan como el mismo atributo. La implementación TypeDescriptor predeterminada omitirá una de las instancias. Si éste no es el comportamiento deseado de un atributo personalizado, como es el caso de la clase FeatureAttribute, el atributo personalizado debe invalidar la propiedad TypeId para devolver un objeto único para cada instancia del tipo. Por ejemplo, la clase FeatureAttribute invalida la propiedad TypeId utilizando el código siguiente.
public override object TypeId
{
get { return this; }
}
Dado que this representa un objeto único para cada instancia de objeto, FeatureAttribute puede decorar varias veces la misma clase sin ningún riesgo y generar el resultado deseado cuando se utiliza junto con el almacén de metadatos.
Convención de nomenclatura para los ensamblados de metadatos
El código de tiempo de diseño se implementa en ensamblados de metadatos especiales. Las características en tiempo de diseño que admiten todos los diseñadores se implementan en un ensamblado con ".Design" anexado al nombre de la biblioteca principal. Las características en tiempo de diseño que admite Visual Studio sólo se implementan en un ensamblado con ".VisualStudio .Design" anexado al nombre de la biblioteca principal. En la siguiente tabla se muestran los nombres de ejemplo para una biblioteca de controles en tiempo de ejecución denominada CustomControlLibrary.dll.
Diseñador |
Nombre del ensamblado en tiempo de diseño |
---|---|
Únicamente Visual Studio |
CustomControlLibrary.VisualStudio.Design.dll |
Únicamente Expression Blend |
CustomControlLibrary.Expression.Design.dll |
Todos los diseñadores |
CustomControlLibrary.Design.dll |
Cargar los ensamblados de metadatos
Cuando el diseñador carga un ensamblado en tiempo de ejecución, el diseñador también busca los ensamblados de metadatos correspondientes. Si se encuentran los ensamblados de metadatos correspondientes, se cargan inmediatamente una vez cargado el ensamblado en tiempo de ejecución.
Cuando se agrega al proyecto una nueva referencia de ensamblado, todos los ensamblados de metadatos correspondientes se buscan y se cargan si se encuentran.
Los ensamblados de metadatos se vuelven a cargar cuando se vuelven a generar.
Nota: |
---|
Los ensamblados de metadatos *.Design.dll se cargan antes de los ensamblados *.VisualStudio.Design.dll y *.Expression.Design.dll específicos del diseñador. Los metadatos específicos del diseñador invalidan los metadatos compartidos. |
Orden de búsqueda de los metadatos del ensamblado
El siguiente orden de búsqueda se aplica a los ensamblados a los que el proyecto hace referencia directamente.
El diseñador busca en la misma carpeta que el ensamblado en tiempo de ejecución al que se hace referencia. Esta ubicación se busca utilizando el mismo algoritmo que la compilación utiliza para buscar el ensamblado, que incluye la búsqueda en las carpetas del SDK y en las rutas de acceso adicionales.
El diseñador busca una subcarpeta “Design” en la carpeta donde se encuentra el ensamblado en tiempo de ejecución del control.
Aunque un ensamblado en tiempo de ejecución del control se puede cargar fuera de la caché de ensamblados global (GAC), la referencia siempre se hace a una ubicación fuera de la GAC. A menudo esta ubicación está en la carpeta del SDK. WPF Designer utiliza las API de Visual Studio para buscar un ensamblado al que se hace referencia en el sistema de archivos, incluso cuando no se especifica el HintPath del proyecto. El diseñador intenta cargar el ensamblado de metadatos desde la ubicación donde se hace referencia al ensamblado en tiempo de ejecución del control, no desde donde se carga el ensamblado en tiempo de ejecución del control.
Los ensamblados a los que se hace referencia indirectamente se cargan porque se hace referencia a ellos desde un ensamblado al que el proyecto hace referencia. Por ejemplo, si tiene un proyecto con una referencia al ensamblado MyAssembly y MyAssembly tiene una referencia a MyOtherAssembly, al que no se hace referencia directamente en el proyecto, se considera que se hace referencia indirectamente a MyOtherAssembly.
En este caso, el ensamblado no se requiere para la compilación y el sistema de compilación no busca la ubicación del ensamblado al que se ha hecho referencia indirectamente en el sistema de archivos. En la siguiente tabla se muestra cómo el diseñador carga los ensamblados a los que se hace referencia indirectamente.
Ensamblado al que se hace referencia |
Procedimiento de búsqueda |
---|---|
Archivo cargado desde la caché de ensamblados global (GAC) |
El ensamblado de metadatos correspondiente se busca en las carpetas del SDK. Si este ensamblado se encuentra, su ruta de acceso y su subcarpeta “Design” se utilizan para buscar cualquier ensamblado de metadatos correspondiente. |
Archivo cargado desde una ubicación fuera de la caché de ensamblados global (GAC) |
El ensamblado de metadatos correspondiente se busca en la ruta de acceso del ensamblado en tiempo de ejecución y su subcarpeta “Design”. |
Buscar una implementación de IRegisterMetadata
Los ensamblados de metadatos deben contener una o más implementaciones de la interfaz IRegisterMetadata. La implementación IRegisterMetadata se encuentra mediante la reflexión. Si en un ensamblado existen varias implementaciones IRegisterMetadata, se crean instancias de cada una y se llaman en el orden devuelto por la API de reflexión.
Vea también
Referencia
Microsoft.Windows.Design.Metadata