Inicio > tiempo de diseño , Silverlight > tiempo de diseño característica de Aplicación de Silverlight Toolkit

Tiempo de diseño característica de Aplicación de Silverlight Toolkit

Introducción

Este es el segundo de mi tiempo de diseño de Silverlight Funciones de la serie. Los primeros correos características en tiempo de diseño de Silverlight Toolkit mostró características de tiempo de diseño de Silverlight Toolkit controles. Este artículo explica cómo se implementa. Espero que este post puede ayudar a explicar nuestro código fuente, lo que demuestra cómo implementar las características de diseño de tiempo para Silverlight, y proporcionar un marco y los lectores de código fuente se puede utilizar directamente en sus propios proyectos.

Información general

Descargar "Silverlight Toolkit - Binarios, muestras, documentación, pruebas unitarias y fuentes" de diciembre 2008 la liberación , SourceSilverlight.Controls.sln abierto en Visual Studio, y vamos a ver que hay 12 proyectos de diseño en la carpeta Diseño de la solución, tres para cada control asamblea.

Silverlight.Controls.sln en Visual Studio

Tome control de proyectos, por ejemplo, hay tres proyectos de diseño:

  • Controls.Design: Windows.Controls.Design.dll construye, que contiene el tiempo de diseño cuenta compartida por Visual Studio y Expression Blend.
  • Controls.Expression.Design: Windows.Controls.Expression.Design.dll construye, que contiene las características de tiempo de diseño Expression Blend solamente.
  • Controls.VisualStudio.Design: Windows.Controls.VisualStudio.Design.dll construye, que contiene las características de tiempo de diseño de Visual Studio solamente.

También hay una carpeta Design.Common que contiene dos archivos: Extensions.cs y MetadataBase.cs, que son compartidos por todos los proyectos de diseño.

Es muy recomendable que lea después de Justin Angel blog de ​​Silverlight Diseño extensibilidad Tiempo : proporciona un buen fondo / vista general de información sobre la extensibilidad de Silverlight en tiempo de diseño, en la que se basa la aplicación a continuación.

Proyecto

Todos los 12 proyectos de diseño sigue las pautas de ejecución misma, por lo que sólo se utilizan los proyectos Control.Design para explicar a todos.

Cargar Silverlight.Controls.sln bajo el directorio principal en Visual Studio por primera vez, vamos a ver la pantalla, como a continuación:

Silverlight.Controls.Design.csproj en Visual Studio

  • Controls.Design tiene una dependencia de proyecto en proyecto de controles. Esta dependencia se asegura que el proyecto de los controles se construyó por primera vez, y Controls.Design tiene una referencia al conjunto de Microsoft.Windows.Controls construido por el proyecto de los controles. Un montaje de tiempo de diseño siempre se hace referencia al ensamblado tiempo de ejecución que proporciona características de diseño de tiempo para.
  • Controls.Design referencias Microsoft.Windows.Design y Microsoft.Windows.Design.Extensibility asambleas, las cuales están bajo PublicAssemblies directorio%% DevEnvDir c: Programa de FilesMicrosoft Visual Studio 9.0Common7IDEPublicAssemblies en mi computadora portátil). Un montaje de tiempo de diseño a menudo referencias los dos conjuntos, que proporcionan el marco de extensibilidad de diseño. Un montaje de tiempo de diseño del sistema de montaje siempre demasiadas referencias, que contiene espacio de nombres System.ComponentModel, donde muchos de los atributos de metadatos (como CategoryAttribute, DescriptionAttribute) se definen.
  • Controls.Design referencias System.Windows asamblea. Podemos ver la referencia en Controls.Design.csproj también:

    <Reference Include="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL">
    <SpecificVersion> False </ SpecificVersion>
    <HintPath> BinariesSystem.Windows.dll .. </ HintPath>
    <Private> False </ privado>
    </ Referencia>

    Tenga en cuenta:

    • Control.Design es una clase de Windows proyecto de biblioteca, no un proyecto de Silverlight, y la Microsoft.Windows.Controls.Design.dll generado es un conjunto de Framework se ejecutan en el escritorio dentro de diseñadores como Visual Studio o Expression Blend, no un conjunto de Silverlight se ejecutan dentro. un navegador, a pesar de que Microsoft.Windows.Controls.Design.dll es el conjunto de tiempo de diseño para la ejecución de Silverlight Microsoft.Windows.Controls.dll tiempo de montaje.
    • La referencia System.Windows conjunto es en realidad un conjunto de Silverlight (versión 2.0.5.0). System.Windows asamblea no puede ser necesaria en todos los proyectos de diseño para los controles de Silverlight. Lo necesitamos aquí más que todo debido a la <T> GetMemberName (Expression <Func <T, object>> expr) método en Extension.cs que vamos a discutir más adelante en el puesto. La mezcla de. NET y las referencias de Silverlight crea todo tipo de temas interesantes, como veremos pronto.

      A continuación ildasm captura de pantalla muestra las referencias mixtas a NET y Silverlight asambleas de Microsoft.Windows.Controls.Design.dll.:
      ildasm Microsoft.Windows.Controls.Design.dll Microsoft.Windows.Controls.Design manifiesto del ensamblado

      • . Ver 2:0:21024:1838 es el número de versión de Silverlight Toolkit versión de diciembre de 2008.
      • . Ver 3:5:0:0 es el número de versión. NET Framework 3.5.
      • . Ver 2:0:0:0 es el número de versión de Silverlight 2.0.
    • Al primer proyecto Controls.Design carga en Visual Studio, hay un "El componente de referencia 'System.Windows" No se pudo encontrar "advertencia junto a la referencia System.Windows Ensamblado en la ventana de proyecto, y en la ventana Lista de errores también. Esto se debe a Controls.Design es un proyecto NET en lugar de Silverlight, y no sabemos donde está instalado Silverlight (que se encuentran en C:. Programa FilesMicrosoft Silverlight2.0.31005.0 en mi portátil, y en C: Archivos de programa (X86 ) Microsoft Silverlight2.0.31005.0 en mi escritorio). La solución es tener un evento previo a la construcción de comandos .. CopySystemWindows.bat que copia System.Windows.dll de Silverlight dirección de instalación para .. Binaries. Así que una vez que haya creado el proyecto, la advertencia va a desaparecer, como veremos en breve.
  • En imagen anterior de Visual Studio, no es otra señal de advertencia al lado de la viuda de Microsoft.Windows.Controls.XML archivo en proyecto, cuando se carga Controls.Design proyecto en Visual Studio por primera vez. Este archivo es generado por la construcción del proyecto depende de los controles, ya que en las propiedades del proyecto de controles -> pestaña Build, la opción "archivo de documentación XML" está marcada, y tiene una trayectoria de ".. Binar
    iesMicrosoft.Windows.Controls.XML ". Si usted construye Controls.Design proyecto, la advertencia va a desaparecer, como veremos en breve.
  • Controls.Design proyecto cuenta con un archivo Metadata.cs, ​​y enlaces a Extension.cs y MetadataBase.cs en la carpeta Design.Common. Todos los 12 proyectos de diseño que esos tres archivos. Vamos a discutir en más detalle más adelante.

Construye el proyecto Controls.Design o toda la solución, podemos ver:

Construir salida de Silverlight.Control.sln

  • Todos los proyectos de construcción muy bien con 0 errores y advertencias 0.
  • Las señales de advertencia junto a System.Windows de referencia y el archivo Microsoft.Windows.Controls.XML desaparecido.
  • El análisis de código del proceso de construcción lleva mucho tiempo, y genera dos advertencias. El primero de ellos, CA0060, es otro de los temas de la mezcla. NET y las referencias de Silverlight y el código de Extension.cs. Usted puede deshacerse de la advertencia copiando System.dll y System.Core.dll del directorio de instalación de Silverlight en el directorio SourceBinaries y construir de nuevo.

MetadataBase.cs

MetadataBase.cs, junto con Metadata.cs, ​​aplicar un marco para el registro de metadatos en tiempo de diseño:

  • DescriptionAttributes se generan automáticamente para las clases de control público (es decir, las subclases de FrameworkElement) y sus propiedades públicas de su "/ / / <summary>" comentarios de documentación XML en el código fuente. (Buenos sueldos comentando! :-) )
  • Para ocultar una clase de control de un diseñador, agregue una línea como la siguiente para el método AddAttributes en el expediente del proyecto Metadata.cs:
    builder.AddCallback (typeof (TreeViewItem), b => (b.AddCustomAttributes ToolboxBrowsableAttribute nueva (falsa)));
  • Para registrar otros atributos personalizados para una clase de control, agregue un archivo XxxMetadata.cs al proyecto, al igual que los ViewboxMetadata.cs discutidas más adelante.

Si te gusta el marco, puede utilizar MetadataBase.cs y Metadata.cs directamente en su propio proyecto, sujeto a licencia pública de Microsoft incluido en el principio de todos nuestros archivos de código fuente.

MetadataBase.cs:

 / / (C) Copyright Microsoft Corporation. / / Esta fuente está sujeto a la Licencia Pública de Microsoft (Ms-PL). / / Por favor, consulte http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles. / o Todos los demás derechos  MetadataRegistrationBase { /// <summary> /// Build design time metadata attribute table. /// </summary> /// <returns>Custom attribute table.</returns> protected virtual AttributeTable BuildAttributeTable() { AttributeTableBuilder builder = new AttributeTableBuilder(); AddDescriptions(builder); AddAttributes(builder); AddTables(builder); return builder.CreateTable(); } /// <summary> /// Find all AttributeTableBuilder subclasses in the assembly /// and add their attributes to the assembly attribute table. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> [SuppressMessage( "Microsoft.Design" , "CA1031:DoNotCatchGeneralExceptionTypes" , Justification = "Design time dll should not fail!" )] private static void AddTables(AttributeTableBuilder builder) { Debug.Assert(builder != null , "AddTables is called with null parameter!" ); Assembly asm = Assembly.GetExecutingAssembly(); foreach (Type t in asm.GetTypes()) { if (t.IsSubclassOf( typeof (AttributeTableBuilder))) { try { AttributeTableBuilder atb = (AttributeTableBuilder)Activator.CreateInstance(t); builder.AddTable(atb.CreateTable()); } catch (Exception e) { Debug.Assert( false , string .Format(CultureInfo.InvariantCulture, "Exception in AddTables method: {0}" , e)); } } } } /// <summary> /// Gets or sets the case sensitive resource name of the embedded XML file. /// </summary> protected string XmlResourceName { get; set; } /// <summary> /// Gets or sets the assembly FullName for types' assembly-qualified names. /// </summary> protected string AssemblyFullName { get; set; } /// <summary> /// Create description attribute from run time assembly xml file. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> [SuppressMessage( "Microsoft.Design" , "CA1031:DoNotCatchGeneralExceptionTypes" , Justification = "Design time dll should not fail." )] private void AddDescriptions(AttributeTableBuilder builder) { Debug.Assert(builder != null , "AddDescriptions is called with null parameter!" ); if ( string .IsNullOrEmpty(XmlResourceName) || string .IsNullOrEmpty(AssemblyFullName)) { return ; } XDocument xdoc = XDocument.Load( new StreamReader( Assembly.GetExecutingAssembly().GetManifestResourceStream(XmlResourceName))); if (xdoc == null ) { return ; } foreach (XElement member in xdoc.Descendants( "member" )) { try { string name = ( string )member.Attribute( "name" ); bool isType = name.StartsWith( "T:" , StringComparison.OrdinalIgnoreCase); if (isType || name.StartsWith( "P:" , StringComparison.OrdinalIgnoreCase)) { int lastDot = name.Length; string typeName; if (isType) { typeName = name.Substring(2); } else { lastDot = name.LastIndexOf( '.' ); typeName = name.Substring(2, lastDot - 2); } typeName += AssemblyFullName; Type t = Type.GetType(typeName); if (t != null && t.IsPublic && t.IsClass && t.IsSubclassOf( typeof (FrameworkElement))) { string desc = member.Descendants( "summary" ).FirstOrDefault().Value; desc = desc.Trim(); desc = string .Join( " " , desc.Split( new char [] { ' ' , 't' , 'n' }, StringSplitOptions.RemoveEmptyEntries)); if (isType) { builder.AddCallback(t, b => b.AddCustomAttributes( new DescriptionAttribute(desc))); } else { string propName = name.Substring(lastDot + 1); PropertyInfo pi = t.GetProperty(propName); MethodInfo mi; if (pi != null && (mi = pi.GetSetMethod()) != null && mi.IsPublic) { builder.AddCallback(t, b => b.AddCustomAttributes(propName, new DescriptionAttribute(desc))); } } } } } catch (Exception e) { Debug.Assert( false , string .Format(CultureInfo.InvariantCulture, "Exception in AddDescriptions method: {0}" , e)); } } } /// <summary> /// Provide a place to add custom attributes without creating a AttributeTableBuilder subclass. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> protected virtual void AddAttributes(AttributeTableBuilder builder) { } } } {/ / / <summary> / / / Clase MetadataRegistration. / / / </ Summary> public class MetadataRegistrationBase {/ / / <summary> / / / Construir el tiempo de diseño metadatos de la tabla de atributos. / / / </ Summary> / / / Custom <returns> tabla de atributos </ rentabilidad> protegida BuildAttributeTable virtuales AttributeTable () {AttributeTableBuilder constructor = new AttributeTableBuilder (); AddDescriptions (constructor); AddAttributes (constructor); AddTables (constructor); builder.CreateTable retorno ();} /. / / <summary> / / / Buscar todas las subclases AttributeTableBuilder en la asamblea / / / y añadir sus atributos a la tabla de atributos de montaje. / / / </ summary> / / / <param name="builder"> La tabla de atributos de la Asamblea constructor </ param>. [SuppressMessage ("Microsoft.Design", "CA1031: DoNotCatchGeneralExceptionTypes", Justificación = "! dll en tiempo de diseño no debe fallar")] static void AddTables privadas (AttributeTableBuilder constructor) {Debug.Assert (constructor =! null, "AddTables se llama con el parámetro nulo!"); Asamblea asm = Assembly.GetExecutingAssembly (); foreach (tipo t en asm.GetTypes ()) {if (t.IsSubclassOf (typeof (AttributeTableBuilder))) {try {AttributeTableBuilder ATB = (AttributeTableBuilder) Activator.CreateInstance (t); builder.AddTable (atb.CreateTable ());} catch (Exception e) {Debug.Assert (falsa, cadena de formato (CultureInfo.InvariantCulture, "Excepción en el método AddTables:. {0} ", e));}}}} / / / <summary> / / / Obtiene o establece el nombre del caso de los recursos sensibles del archivo incrustado XML / / / </ summary> XmlResourceName cadena de protección {get;. establece ;} / / / <summary> / / / Obtiene o establece el FullName de montaje para los tipos cualificados de la Asamblea los nombres de / / / </ summary> AssemblyFullName cadena de protección {get;. puesto;} / / / <summary> / / / Crear atributo de descripción del archivo de ensamblado de tiempo de ejecución xml / / / </ summary> / / / <param name="builder"> El atributo de ensamblado generador de tablas </ param> [SuppressMessage ("Microsoft.Design", "CA1031..: DoNotCatchGeneralExceptionTypes ", Justificación =" dll en tiempo de diseño no debe fracasar ")] private void (AddDescriptions AttributeTableBuilder constructor) {Debug.Assert (constructor = null," AddDescriptions se llama con el parámetro nulo ");.!. si (string IsNullOrEmpty ( XmlResourceName) | | cadena de IsNullOrEmpty (AssemblyFullName)) {return;} XDocument xdoc XDocument.Load = (new StreamReader (Assembly.GetExecutingAssembly ().. GetManifestResourceStream (XmlResourceName))) if (xdoc == null) {return;} foreach (miembro de xdoc.Descendants XElement ("miembro")) {try {nombre de la cadena = (cadena) member.Attribute ("nombre"); bool istype = name.StartsWith ("T", StringComparison.OrdinalIgnoreCase), si ( istype | | name.StartsWith ("P", StringComparison.OrdinalIgnoreCase)) {int lastDot name.Length =; typeName cadena, si (istype) {typeName name.Substring = (2);} else {lastDot = name.LastIndexOf ('.'); TypeName name.Substring = (2, lastDot - 2);} TypeName AssemblyFullName + =; tipo t = Type.GetType (typeName) if (t = null && && t.IsPublic && t.IsClass t.IsSubclassOf (typeof (FrameworkElement))) {String desc = member.Descendants ("Resumen") FirstOrDefault (); Valor. desc.Trim. desc = ();. desc = cadena de Ingreso ("", (desc.Split new char [] {'', 't', 'n'}, StringSplitOptions.RemoveEmptyEntries)) if (istype) {builder.AddCallback (t, b => (b.AddCustomAttributes DescriptionAttribute nueva (desc)));} else {cadena = propName name.Substring lastDot (+ 1); PropertyInfo pi = t.GetProperty (propName); MethodInfo millas;! if (pi = null && (MI = pi.GetSetMethod ()) = null && mi.IsPublic ) {builder.AddCallback (t, b => b.AddCustomAttributes (propName, DescriptionAttribute nueva (desc)));}}}}} catch (Exception e) {Debug.Assert (falsa, cadena de formato (CultureInfo.InvariantCulture,. "Excepción en el método AddDescriptions: {0}"., e));}}} / / / <summary> / / / Proporcionar un lugar para añadir atributos personalizados sin necesidad de crear una subclase AttributeTableBuilder / / / </ summary> / / / <param name="builder"> El atributo de ensamblado generador de tablas. </ param> AddAttributes protegidas virtual void (AttributeTableBuilder constructor) {}}} 

MetadataBase.cs implementa la clase MetadataRegistrationBase. Vamos a discutir algunos de los métodos de sus claves:

AddDescriptions

Todos los proyectos de tiempo de ejecución de montaje han "archivo de documentación XML" opción activada, y con una trayectoria como ".. BinariesMicrosoft.Windows.Controls.XML", en el Proyecto -> Propiedades -> pestaña Build, la sección de salida. También puede encontrar el ajuste en el csproj como a continuación.:

  > ..BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile > <DocumentationFile> .. BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile> 

A continuación se muestra un extracto de Microsoft.Windows.Controls.XML para mostrar lo que la documentación de archivo XML generado se ve así:

 un decorador de contenido que se puede estirar y escalar un solo niño para llenar la disposición  del elemento secundario en su defecto de Viewbox  > < param name ="o" > The object typed value to be checked. </ param > < returns > True if o is a valid Stretch enum value, false o/w. </ returns > </ member > < member name ="P:Microsoft.Windows.Controls.Viewbox.Child" > < summary > Gets or sets the single child element of a Viewbox. </ summary > </ member > </ members > </ doc > si el pasado en objeto de valor es un valor de enumeración Stretch válida. </ resumen> <param name = "o"> El valor del objeto con tipo para ser revisado. </ param> <regresa> True si o es una exageración válida valor de enumeración, falsa o / w </ rentabilidad> </ member> <nombre de usuario = "P: Microsoft.Windows.Controls.Viewbox.Child">.. <> Resumen Obtiene o establece el elemento secundario de un Viewbox </ resumen> < / member> </ miembros> </ doc> 

El atributo de nombre de cada elemento <miembro> sigue el patrón:

  • "T: Microsoft.Windows.Controls.Viewbox": "T" indica que es un tipo, seguido por el nombre completo del tipo de;
  • "F: Microsoft.Windows.Controls.Viewbox.ChildElementName": "F:" indica que este es un campo, seguido por el nombre del campo es completo;
  • "M: Microsoft.Windows.Controls.Viewbox.IsValidStretchValue (System.Object)": "M" indica que este es un método, seguido por el método es el nombre completo y los parámetros;
  • "P: Microsoft.Windows.Controls.Viewbox.Child": "P:" indica que se trata de una propiedad, seguido por el nombre completo de la propiedad;

Control.Design proyecto conecta con el archivo Microsoft.Windows.Controls.XML como un recurso incrustado:

  • Microsoft.Windows.Controls.XML como recurso incrustado
  • Controls.Design.csproj:

     Include ="..BinariesMicrosoft.Windows.Controls.XML" /> <EmbeddedResource Incluir = ".. BinariesMicrosoft.Windows.Controls.XML" /> 

Método de AddDescriptions analiza el archivo XML y genera incrustado DescriptionAttribute para las clases de control público y sus propiedades públicas:

  MetadataBase.cs: 134: builder.AddCallback (t, b => b.AddCustomAttributes (DescriptionAttribute nueva (desc)));
 MetadataBase.cs: 143: builder.AddCallback (t, b => (b.AddCustomAttributes propName, DescriptionAttribute nueva (desc))); 
AddAttributes

AddAttributes es por lo general se reemplaza en el archivo Metadata.cs para añadir un ToolboxBrowsableAttribute (falsa) de atributos personalizados para las clases de control que no debe aparecer en una caja de herramientas del diseñador:

  • si la clase de control deben ser ocultados de todos los diseñadores, agregue el ToolboxBrowsableAttribute (falsa) de atributos personalizados al proyecto Xxx.Design;
  • si deben ser ocultados de Visual Studio sólo, agregue el atributo personalizado al proyecto Xxx.VisualStudio.Design;
  • si deben ser ocultados de Expression Blend única, agregue el atributo personalizado al proyecto Xxx.Expression.Design;

A continuación se muestra la aplicación en AddAttributes Metadata.cs del proyecto Controls.VisualStudio.Design:

  / / / <summary>
 / / / Proporcionar un lugar para añadir atributos personalizados sin necesidad de crear una subclase AttributeTableBuilder.
 / / / </ Summary>
 / / / <param Name="builder"> El atributo de ensamblado generador de tablas. </ Param>
 protegidas AddAttributes override void (AttributeTableBuilder constructor)
 {
     ToolboxBrowsableAttribute( false ))); builder.AddCallback (typeof (TreeViewItem), b => (b.AddCustomAttributes ToolboxBrowsableAttribute nueva (falsa)));
 } 
AddTables

Para agregar atributos que no sean ToolboxBrowsableAttribute (falsa) de un tipo, agregar un archivo XxxMetadata.cs como ViewboxMetadata.cs a continuación para el proyecto de diseño apropiado:

ViewboxMetadata.cs:

 / / (C) Copyright Microsoft Corporation. / / Esta fuente está sujeto a la Licencia Pública de Microsoft (Ms-PL). / / Por favor, consulte http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles. / o Todos los demás derechos  ViewboxMetadata : AttributeTableBuilder { /// <summary> /// To register design time metadata for Viewbox. /// </summary> public ViewboxMetadata() : base () { AddCallback( typeof (Viewbox), b => { b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.BorderThickness), new BrowsableAttribute( false )); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.BorderBrush), new BrowsableAttribute( false )); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.Background), new BrowsableAttribute( false )); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.Foreground), new BrowsableAttribute( false )); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.Child), new CategoryAttribute(Properties.Resources.CommonProperties)); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.Stretch), new CategoryAttribute(Properties.Resources.CommonProperties)); b.AddCustomAttributes(Extensions.GetMemberName<Viewbox>(x => x.StretchDirection), new CategoryAttribute(Properties.Resources.CommonProperties)); }); } } } {/ / / <summary> / / / Para registrar los metadatos en tiempo de diseño para el Viewbox / / / </ summary> interna ViewboxMetadata clase:.. AttributeTableBuilder {/ / / <summary> / / / Para registrar los metadatos en tiempo de diseño para el Viewbox / / / </ summary> public ViewboxMetadata (): base () {addCallback (typeof (Viewbox), b => {b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.BorderThickness>), nueva BrowsableAttribute (false)) ; b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.BorderBrush), nueva BrowsableAttribute (false)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Background), BrowsableAttribute nueva (falsa )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.Foreground>), nueva BrowsableAttribute (false)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Child), CategoryAttribute nueva (Properties.Resources.CommonProperties)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Stretch), CategoryAttribute nueva (Properties.Resources.CommonProperties)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> ( x = x.StretchDirection>), CategoryAttribute nueva (Properties.Resources.CommonProperties));});}}} 
  • Se recomienda seguir la convención de nombres aquí. Tome Viewbox por ejemplo, el nombre del archivo es ViewboxMetadata.cs, ​​y el nombre de la clase es ViewboxMetadata.
  • La clase de metadatos debe heredar de AttributeTableBuilder.
  • Puede agregar atributos personalizados en el constructor de la clase de metadatos:
    • Usted puede utilizar el modelo de devolución de llamada (como en ViewboxMetada.cs anteriores) o el modelo directo. El modelo de devolución de llamada que supuestamente es más eficiente.
      • ejemplo de modelo directo:

        (AddCustomAttributes

        typeof (Viewbox), / / ​​tipo

        "BorderThickness", / / ​​nombre de la propiedad

        Atributo new [] {BrowsableAttribute nueva (false)}); / / matriz de atributos personalizados

    • Para proporcionar el parámetro de nombre de la propiedad a la llamada de AddCustomAttribute, puede utilizar el método de Extensions.GetMemberName () como en ViewboxMetadata.cs (hablaremos más sobre esto más adelante en el cargo) para obtener el nombre de la propiedad de una manera segura de tipo, o proporcionar el nombre de la propiedad directamente como cadena como "BorderThickness" en la aplicación directa del modelo anterior.

El AddTables (AttributeTableBuilder constructor) método:

  • enumera todas las subclases de AttributeTableBuilder en el conjunto de la ejecución de
  • crea una instancia de cada subclase AttributeTableBuilder encontrado:

    AttributeTableBuilder ATB = (AttributeTableBuilder) Activator.CreateInstance (t);

  • agregar la tabla de atributos de la clase encontró al constructor:

    builder.AddTable (atb.CreateTable ());

Metadata.cs

Metadata.cs implementa MetadataRegistration clase, que hereda de la clase MetadataRegistrationBase implementado en MetadataBase.cs. También implementa IRegisterMetadata interfaz.

Metadata.cs:

 / / (C) Copyright Microsoft Corporation. / / Esta fuente está sujeto a la Licencia Pública de Microsoft (Ms-PL). / / Por favor, consulte http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles. / o Todos los demás derechos  MetadataRegistration : MetadataRegistrationBase, IRegisterMetadata { /// <summary> /// Design time metadata registration class. /// </summary> public MetadataRegistration() : base () { AssemblyName asmName = typeof (Viewbox).Assembly.GetName(); XmlResourceName = asmName.Name + ".Design." + asmName.Name + ".XML" ; // "Microsoft.Windows.Controls.Design.Microsoft.Windows.Controls.XML" AssemblyFullName = ", " + asmName.FullName; } /// <summary> /// Borrowed from System.Windows.Controls.Toolbox.Design.MetadataRegistration: /// use a static flag to ensure metadata is registered only one. /// </summary> private static bool _initialized; /// <summary> /// Called by tools to register design time metadata. /// </summary> public void Register() { if (!_initialized) { MetadataStore.AddAttributeTable(BuildAttributeTable()); _initialized = true ; } } /// <summary> /// Provide a place to add custom attributes without creating a AttributeTableBuilder subclass. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> protected override void AddAttributes(AttributeTableBuilder builder) { } } } . {/ / / <summary> / / / Clase MetadataRegistration / / / </ summary> public class MetadataRegistration:. MetadataRegistrationBase, IRegisterMetadata {/ / / <summary> / / / Diseño de metadatos tiempo de la clase de registro / / / </ summary> MetadataRegistration pública ():. base () {AssemblyName asmName = typeof (Viewbox) Assembly.GetName (); XmlResourceName asmName.Name = + ".. Diseño" + + asmName.Name ". XML" / / "Microsoft.Windows . Controls.Design.Microsoft.Windows.Controls.XML "AssemblyFullName =", "+ asmName.FullName;} / / / <summary> / / / Tomado de System.Windows.Controls.Toolbox.Design.MetadataRegistration: / / / utilizar una bandera estática para garantizar los metadatos se ha registrado una sola / / / </ summary> private static bool _initialized;. / / / <summary> / / / Llamado por las herramientas para registrar los metadatos en tiempo de diseño / / / </ summary> public. anular Register () {if {MetadataStore.AddAttributeTable (BuildAttributeTable ()) (_initialized!); _initialized = true;}}. / / / <summary> / / / Proporcionar un lugar para añadir atributos personalizados sin necesidad de crear una subclase AttributeTableBuilder / / / </ summary> / / / <param name="builder"> El atributo de ensamblado generador de tablas. </ param> protected override void (AddAttributes AttributeTableBuilder constructor) {}}} 

Vamos a discutir algunos de sus métodos principales:

MetadataRegistration

Este constructor inicializa dos campos principales:

  • XmlResourceName: nombre del recurso de la documentación integrada de archivos XML, utilizado por el método de MetadataRegistrationBase.AddDescriptions.
  • AssemblyFullName: nombre completo del conjunto de tiempo de ejecución esta asamblea el tiempo de diseño es para.

Es necesario sustituir el tipo de Viewbox con su propia clase si utiliza Metadata.cs en su proyecto de diseño propio.

Registrar

Este es el único método de IRegisterMetadata interfaz. Se agrega la tabla de atributos personalizados, construido a partir de AddDescripions y AddAttributes y AddTables métodos descritos anteriormente, para almacén de metadatos diseñador:

MetadataStore.AddAttributeTable (BuildAttributeTable ());

Extensions.cs

Este archivo contiene la implementación del método de extensión <T> GetMemberName (Expression <Func <T, object>> expr) que se utiliza para obtener el nombre de un miembro de un tipo con un chequeo en tiempo de compilación y de IntelliSense:

GetMemberName método de extensión

La idea fue propuesta originalmente por Jafar Husain (ver su blog símbolos en C # 3.0 ), y luego mejorada por Justin Angel . Es un buen truco para evitar errores, pero el inconveniente es que se tira en las referencias de Silverlight y asambleas de otro modo en un puro. NET. Aquí está el código fuente completo:

Extensions.cs:

  / / (C) Copyright Microsoft Corporation.
 / / Este código está sujeto a la Licencia Pública de Microsoft (Ms-PL).
 / / Por favor, consulte http://go.microsoft.com/fwlink/?LinkID=131993 para más detalles.
 / / Todos los demás derechos reservados.

 using System;
 utilizando System.Linq.Expressions;

 espacio de nombres Microsoft.Windows.Controls.Design.Common
 {
     / / / <summary>
     / / / Este conjunto de métodos de extensión internos proporcionan soluciones generales y
     / / / Empresas de servicios públicos en un número lo suficientemente pequeño como para no requerir una extensión dedicada
     / / / Métodos de la clase.
     / / / </ Summary>
     internos de clase estática Extensions
     {
         / / / <summary>
         / / / Método de ayuda para obtener el nombre de los miembros de la verificación en tiempo de compilación para evitar error tipográfico.
         / / / </ Summary>
         / / / <typeparam Name="T"> la clase que contiene el miembro cuyo nombre se recupera. </ Typeparam>
         / / / <param Name="expr"> La expresión lambda usualmente en la forma de o => o.member. </ Param>
         / / / <returns> El nombre de la propiedad. </ Rentabilidad>
         >> expr) public static string GetMemberName <T> (Expression <Func <T, object>> expr)
         {
             Expresión corporal = ((LambdaExpression) expr) Cuerpo.;
             MemberExpression MemberExpression = cuerpo como MemberExpression;
             ) if (MemberExpression == null)
             {
                 MemberExpression = (MemberExpression) ((objeto UnaryExpression) del cuerpo) operando.;
             }
             volver memberExpression.Member.Name;
         }
     }
 } 

Conclusión

Este artículo describe la implementación de características en tiempo de diseño en el 12 2008 de liberación de Silverlight Toolkit , e introdujo un marco sencillo para la aplicación de función de tiempo de diseño para los controles de Silverlight. Usted puede modelar la aplicación y volver a utilizar el marco de sus propios proyectos. El marco es todavía muy primitivo, el apoyo a los metadatos de registro único, ya que eso es todo lo soporta mezcla por ahora. Voy a mirar en la mejora del marco y las características de tiempo de diseño para Silverlight Toolkit, como la adición de los editores personalizados en línea / extendido / de diálogo, los datos de tiempo de diseño, en tiempo de diseño sólo los comportamientos, etc

Como he dicho en anteriores post características en tiempo de diseño de Silverlight Toolkit , las experiencias en tiempo de diseño para los controles son muy importantes. No sólo mejora la experiencia y la productividad de los desarrolladores que utilizan los controles con características de tiempo se dignan, sino que también mejora la experiencia de los usuarios finales, ya que más y más aplicaciones a los usuarios una mayor flexibilidad en la personalización de la interfaz de usuario, como cambiar el diseño de arrastrar y soltar los controles de , o cambiar la configuración de un control, al igual que en un diseñador, si no es en tiempo de ejecución.

  1. 21 de abril 2009 a las 08:19 | # 1

    @ FIDER
    Para la depuración, intente lo siguiente:
    * Asegúrese de que el nombramiento y la ubicación de su control y las asambleas de diseño son correctos, es decir, si el conjunto de control es foo.dll en c: \ tmp, entonces el conjunto de diseño es foo.design.dll en c: \ tmp oc: \ tmp \ Diseño.
    * Abra el proyecto de diseño situado a un punto de interrupción en su función de registro, y se fijó el objetivo de depuración de la propiedad del proyecto de diseño para el lanzamiento de Visual Studio
    * Presionar F5, una instancia de VS se pone en marcha nueva, crear un nuevo proyecto de SL, y luego ir a través del diálogo Elegir elementos, seleccione la ficha de Silverlight, vaya a la carpeta c: \ tmp y seleccione su foo.dll dll de control.
    * El punto de interrupción debe golpear.

    Otra causa común de problemas: asegúrese de que es el tipo de Silverlight (TreeViewItemAdv en el ejemplo) se van a especificar los metadatos de.

    Espero que esto ayude!

    Gracias,

    -Ning

  2. FIDER
    21 de abril 2009 a las 03:18 | # 2

    Hola Ning,

    He creado como asambleas y se coloca en una carpeta local y el GAC. Estoy tratando de abrir las asambleas de la carpeta local en el diálogo de elegir los elementos - Silverlight ficha Componentes. Su selecciona todas las clases en las asambleas y se añaden al cuadro de herramientas.

    Así que quiero saber cómo puedo depurar estos proyectos

    Un cordial saludo,
    FIDER

  3. FIDER
    20 de abril 2009 a las 04:04 | # 3

    Hola Ning,

    Buen artículo. He creado el diseño y proyecto de visualstudio.design para mi control personalizado de Silverlight. Mi objetivo es sólo para ocultar una clase de la caja de herramientas. Tengo un archivo donde en metadata.cs he puesto ToolboxBrowsableAttribute a false para las clases que deben ser hidded. Mi archivo metadata.cs tiene el siguiente aspecto.

    metadatos de la clase pública: IRegisterMetadata
    {

    Registrarse public void ()
    {
    AttributeTableBuilder constructor = new AttributeTableBuilder ();
    builder.AddCallback (typeof (TreeViewItemAdv), b => (b.AddCustomAttributes ToolboxBrowsableAttribute nueva (falsa)));
    MetadataStore.AddAttributeTable (builder.CreateTable ());
    }
    }

    Pero todavía podría conseguir la clase que se muestra.

    Cualquier ayuda será apreciable.

    Un cordial saludo,

    FIDER.

    • 20 de abril 2009 a las 14:52 | # 4

      Hola FIDER,

      Su código es correcto. Mi sugerencia es que paso a paso para verificar el código es cargado y ejecutado correctamente:
      * Establezca un punto de interrupción en su función de registro y ver si se ve afectado. VS2010 y Blend3 MWD uso más reciente y un punto de entrada diferente (IProvideAttributeTable.AttributeTable lugar de IRegisterMetadata.Register), y si el nombre o la ubicación de la DLL de diseño no es correcta en relación con la dll en tiempo de ejecución correspondiente, el archivo DLL de diseño no se cargado tampoco. Esta es una causa común de los problemas.
      * Si su punto de ruptura se ve afectado, el paso a través de su código, a continuación, compruebe el efecto, a través de AttributeTable.GetCustomAttributes AttributeTable.ValidateTable,, o TypeDescriptor.GetAttributes etc

      Espero que esto ayude.

      Gracias,

      -Ning

  1. 21 de enero 2009 a las 18:31 | # 1
  2. 24 de enero 2009 a las 20:24 | # 2
  3. 31 de marzo 2009 a las 02:16 | # 3
  4. 03 de abril 2009 a las 11:48 | # 4
  5. 22 de abril 2009 a las 23:17 | # 5
  6. 11 de Mayo de 2009 a las 13:14 | # 6