Archives

Archive pour 2008

Temps de mise en œuvre d'entité Design dans Silverlight Toolkit

28 décembre 2008 4 commentaires

Introduction

Ceci est le deuxième volet de ma série Design Silverlight intègre Time. Le premier poste Design intègre Time dans Silverlight Toolkit a montré des caractéristiques de la conception de Silverlight Toolkit contrôles. Ce message explique comment il est mis en œuvre. Espérons que ce poste peut vous aider en expliquant notre code source, montrant comment implémenter des fonctionnalités de la conception pour Silverlight, et en fournissant un cadre et des lecteurs de code source peut utiliser directement dans leurs propres projets.

Vue d'ensemble

Télécharger "Silverlight Toolkit - Binaries, échantillons, documentation, tests unitaires et« Sources de Décembre 2008 Communiqué , ouvrez SourceSilverlight.Controls.sln dans Visual Studio, et nous verrons qu'il ya de conception de 12 projets en vertu de dossier de la solution de conception, trois pour chaque contrôle Assemblée.

Silverlight.Controls.sln dans Visual Studio

Prenez projet contrôles par exemple, il ya trois projets de conception:

  • Controls.Design: construit Windows.Controls.Design.dll, qui contient le temps de conception des caractéristiques partagées par les deux Visual Studio et Expression Blend.
  • Controls.Expression.Design: construit Windows.Controls.Expression.Design.dll, qui contient des caractéristiques de la conception pour Expression Blend seulement.
  • Controls.VisualStudio.Design: construit Windows.Controls.VisualStudio.Design.dll, qui contient des caractéristiques de la conception pour Visual Studio.

Il ya aussi un dossier Design.Common qui contient deux fichiers: Extensions.cs et MetadataBase.cs, qui sont partagés par tous les projets de conception.

Il est fortement recommandé de lire Justin Angel's blog Silverlight moment du design d'extensibilité : il fournit des informations de fond bonne vue d'ensemble / extension sur la conception du temps Silverlight, sur lequel la mise en œuvre ci-dessous est basée.

Projet

Tous les 12 projets de conception suivre le modèle de mise en œuvre même, alors je vais juste utiliser projet Control.Design pour expliquer tous.

Silverlight.Controls.sln charge sous Source répertoire dans Visual Studio pour la première fois, nous allons voir l'écran, comme ci-dessous:

Silverlight.Controls.Design.csproj dans Visual Studio

  • Controls.Design a une dépendance du projet sur le projet de contrôles. Cette dépendance assure que le projet Controls est construit le premier, et Controls.Design a une référence à l'assembly Microsoft.Windows.Controls projet construit par des contrôles. Une assemblée moment de la conception toujours des références de l'Assemblée moment de l'exécution il fournit des fonctionnalités de conception pour le temps.
  • références Controls.Design Microsoft.Windows.Design et assemblages Microsoft.Windows.Design.Extensibility, qui sont tous deux sous PublicAssemblies% répertoire% DevEnvDir (C: \ Program FilesMicrosoft Visual Studio 9.0Common7IDEPublicAssemblies sur mon ordinateur portable). Une assemblée moment de la conception souvent des références de ces deux ensembles, qui constituent le cadre d'extensibilité designer. Un ensemble toujours le temps de conception références système de montage aussi, qui contient l'espace de noms System.ComponentModel, où la plupart des métadonnées attributs (comme CategoryAttribute, DescriptionAttribute) sont définies.
  • références Controls.Design System.Windows Assemblée. Nous pouvons voir la référence dans Controls.Design.csproj aussi:

    <Référence Include="System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL">
    <SpecificVersion> False <> SpecificVersion /
    <HintPath> .. BinariesSystem.Windows.dll </> HintPath
    <Private> False </> Privé
    /> Référence <

    S'il vous plaît noter:

    • Control.Design est un Windows projet Bibliothèque de classes, pas un projet Silverlight, et le produit Microsoft.Windows.Controls.Design.dll est un assembly. NET exécuter sur le bureau de l'intérieur des designers tels que Visual Studio ou Expression Blend, pas une assemblée Silverlight fonctionnent à l'intérieur un navigateur, même si l'Assemblée est Microsoft.Windows.Controls.Design.dll moment du design pour la Microsoft.Windows.Controls.dll Silverlight moment de l'exécution de l'Assemblée.
    • L'assemblage référencé System.Windows est en fait un assemblage Silverlight (version 2.0.5.0). Assemblée System.Windows peuvent ne pas être nécessaires à tous les projets de design pour les contrôles Silverlight. Nous en avons besoin ici surtout à cause de la <T> GetMemberName (Expression <Func <T, object>> expr) méthode Extension.cs que nous discuterons plus tard dans le poste. Le mélange de. NET et Silverlight références crée toutes sortes de questions intéressantes, comme nous le verrons bientôt.

      capture d'écran ci-dessous montre ildasm les références mixtes. NET et Silverlight assemblées par Microsoft.Windows.Controls.Design.dll:
      ildasm Microsoft.Windows.Controls.Design.dll Assemblée Microsoft.Windows.Controls.Design manifeste

      • . 2:0:21024:1838 ver est le numéro de version de Silverlight Toolkit 2008 Communiqué de Décembre.
      • . 3:5:0:0 ver est le numéro de version. NET Framework 3.5.
      • . 2:0:0:0 ver est le numéro de version de Silverlight 2.0.
    • Lorsque vous chargez premier projet Controls.Design dans Visual Studio, il ya un "Le composant référencé 'System.Windows' n'a pas pu être trouvé" d'alerte à côté de la référence d'assembly System.Windows dans la fenêtre de projet, et dans la fenêtre Liste d'erreurs aussi. C'est parce que Controls.Design NET est un projet. Lieu de Silverlight, et nous ne savons pas où Silverlight est installé (il est sous C: Program FilesMicrosoft Silverlight2.0.31005.0 sur mon portable, et sous C: Program Files (x86 ) Silverlight2.0.31005.0 Microsoft sur mon bureau). La solution est d'avoir une pré-commande de construction événement .. CopySystemWindows.bat que des copies de Silverlight System.Windows.dll installer des binaires .. direction. Donc, une fois que vous avez construit le projet, la mise en garde vont disparaître, comme nous le verrons bientôt.
  • En dessus de Visual Studio capture d'écran, il est un autre signe d'alerte à côté de la Microsoft.Windows.Controls.XML fichier dans la veuve du projet, lorsque vous chargez Controls.Design projet dans Visual Studio pour la première fois. Ce fichier est généré par la construction du projet à charge des contrôles, car dans les propriétés du projet de contrôles -> Build onglet, l'option "fichier de documentation XML" est coché, et a un chemin de ".. Binar
    "IesMicrosoft.Windows.Controls.XML. Si vous construisez projet Controls.Design, l'avertissement disparaîtra, comme nous le verrons bientôt.
  • Controls.Design projet a un fichier Metadata.cs, et des liens vers Extension.cs et MetadataBase.cs dans le dossier Design.Common. Tous les 12 projets de conception ont ces trois fichiers. Nous allons en discuter plus en détail plus tard.

Construire Controls.Design projet ou la solution ensemble, nous pouvons voir:

Construire de sortie Silverlight.Control.sln

  • Tous les projets construits amende avec 0 erreurs et 0 avertissements.
  • Les signes d'alerte à côté de référence System.Windows et Microsoft.Windows.Controls.XML fichier disparu.
  • L'analyse de code du processus de création prend beaucoup de temps, et il génère deux avertissements. Le premier, CA0060, est une autre question de l'mixtes. NET et les références Silverlight et le code de Extension.cs. Vous pouvez vous débarrasser de l'avertissement en copiant System.dll et System.Core.dll du répertoire d'installation de Silverlight au répertoire SourceBinaries et le renforcement de nouveau.

MetadataBase.cs

MetadataBase.cs, avec Metadata.cs, mettre en œuvre un cadre pour l'enregistrement des métadonnées de conception du temps:

  • DescriptionAttributes sont générés automatiquement pour les classes de contrôle public (par exemple, sous-classes de FrameworkElement) et leurs propriétés publiques de leur "/ / / <summary>" les commentaires de documentation XML dans le code source. (Bon commentant paie! :-) )
  • Pour masquer une classe de contrôle à partir d'un designer, ajouter une ligne comme ci-dessous pour la méthode AddAttributes dans Metadata.cs du projet de fichier:
    builder.AddCallback (typeof (TreeViewItem), b => b.AddCustomAttributes (nouveau ToolboxBrowsableAttribute (false)));
  • Pour vous inscrire d'autres attributs personnalisés pour une classe de contrôle, ajouter un XxxMetadata.cs fichier au projet, comme le ViewboxMetadata.cs discuté plus tard.

Si vous aimez le cadre, vous pouvez utiliser MetadataBase.cs et Metadata.cs directement dans votre propre projet, sous réserve de Microsoft Public License inclus au début de tous nos fichiers source.

MetadataBase.cs:

 System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Windows; using System.Xml.Linq; using Microsoft.Windows.Design.Metadata; namespace Microsoft.Windows.Controls.Design.Common { /// <summary> /// MetadataRegistration class. /// </summary> public class 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) { } } } / / (C) Copyright Microsoft Corporation. / / Cette source est soumis à la Microsoft Public License (Ms-PL). / / S'il vous plaît voir http://go.microsoft.com/fwlink/?LinkID=131993 pour plus de détails. / / Tous les autres droits réservés. using System; utilisant System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; utilisant System.Diagnostics.CodeAnalysis; utilisant System.Globalization; using System.IO; utilisant System.Linq; using System . Linq.Expressions; using System.Reflection; utiliser System.Windows; utilisant System.Xml.Linq; utilisant Microsoft.Windows.Design.Metadata; espace de noms Microsoft.Windows.Controls.Design.Common (/ / / <summary> / / / classe MetadataRegistration. / / / </ summary> public class MetadataRegistrationBase (/ / / <summary> / / / design métadonnées en temps Build attribut table. / / / / summary> </ / / table des attributs personnalisés <returns>. </ > Retours virtuelle protégée AttributeTable BuildAttributeTable () (constructeur AttributeTableBuilder = new AttributeTableBuilder (); AddDescriptions (constructeur); AddAttributes (constructeur); AddTables (constructeur); retour builder.CreateTable ();) / / / <summary> / / / Trouver tous les sous-classes AttributeTableBuilder à l'Assemblée / / / et ajouter leurs attributs à la table des attributs de montage. / / / / summary> </ / <param name="builder"> / Le tableau constructeur attribut d'assembly. </ param> [SuppressMessage ( "Microsoft.Design", "CA1031: DoNotCatchGeneralExceptionTypes", Justification = "dll de temps de conception ne doit pas manquer!")] static void privé AddTables (constructeur AttributeTableBuilder) (Debug.Assert (constructeur! = null, "AddTables est appelée avec le paramètre null ! "); asm l'Assemblée Assembly.GetExecutingAssembly = (); foreach (type T dans asm.GetTypes ()) (if (t.IsSubclassOf (typeof (AttributeTableBuilder))) (try (ATB AttributeTableBuilder = (AttributeTableBuilder) Activator.CreateInstance ( t); builder.AddTable (atb.CreateTable ());) catch (Exception e) (Debug.Assert (false, chaîne de caractères. Format (CultureInfo.InvariantCulture, "Exception de la méthode AddTables: (0)", e)); )))) / / / <summary> / / / Obtient ou définit le nom de la ressource cas sensibles du fichier XML intégré. / / / / summary> <protégées XmlResourceName chaîne (get; ensemble;) / / / <summary> / / / Obtient ou définit le FullName Assemblée pour 'Assemblée qualifiés noms types. / / / / summary> <protégées AssemblyFullName chaîne (get; ensemble;) / / / <summary> / / / Créer un attribut de description XML de temps de montage fichier d'exécution . / / / / summary> </ / <param name="builder"> / Le tableau constructeur attribut d'assembly. </ param> [SuppressMessage ("Microsoft.Design", "CA1031: DoNotCatchGeneralExceptionTypes", Justification = "temps de conception dll ne devrait pas manquer. ")] AddDescriptions private void (constructeur AttributeTableBuilder) (Debug.Assert (constructeur! = null," AddDescriptions est appelée avec le paramètre null! "), si (string. IsNullOrEmpty (XmlResourceName) | | chaîne. IsNullOrEmpty (AssemblyFullName )) (return;) xdoc XDocument = XDocument.Load (new StreamReader (Assembly.GetExecutingAssembly (). GetManifestResourceStream (XmlResourceName))); if (xdoc == null) (return;) foreach (membre XElement dans xdoc.Descendants (" membres ")) (try (String nom = (string) member.Attribute (" nom "); isType bool = name.StartsWith (" T: ", StringComparison.OrdinalIgnoreCase), si (| | name.StartsWith isType (" P », StringComparison.OrdinalIgnoreCase)) (= int lastDot name.Length; chaîne; typeName if (isType) (= typeName name.Substring (2);) else (lastDot = name.LastIndexOf ('.'); typeName = nom: Sous-chaîne (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 (). Valeur; desc desc.Trim = (); desc = string. join ("", desc.Split (nouveau char [] (',' t ',' n '), StringSplitOptions.RemoveEmptyEntries)); if (isType) (builder.AddCallback (t, => b.AddCustomAttributes (nouveau DescriptionAttribute (desc)));) else (b = propName chaîne name.Substring ( lastDot 1); PropertyInfo = pi t.GetProperty + (propName); mi MethodInfo, si (pi! = null & & (mi = pi.GetSetMethod ())! = null & & mi.IsPublic) (builder.AddCallback (t, b => b.AddCustomAttributes (propName, nouvelle DescriptionAttribute (desc)));))))) catch (Exception e) (Debug.Assert (false, chaîne de caractères. Format (CultureInfo.InvariantCulture, "Exception de la méthode AddDescriptions: (0) », e));))) / / / <summary> / / / Fournir un lieu d'ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder. / / / / summary> </ / <param name="builder"> / Le Table Builder attribut d'assembly. / param> <protégées virtual void AddAttributes (constructeur AttributeTableBuilder) ())) 

MetadataBase.cs implémente la classe MetadataRegistrationBase. Let's discuter de certaines de ses principales méthodes:

AddDescriptions

Tous les projets menés Assemblée temps ont "fichier de documentation XML" option est cochée, et avec un chemin comme ".. BinariesMicrosoft.Windows.Controls.XML", dans le projet -> Propriétés -> onglet Build, section de sortie. Vous trouverez également la mise en. Csproj fichier comme ci-dessous:

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

Voici un extrait de Microsoft.Windows.Controls.XML pour montrer ce que la documentation générée fichier XML ressemble à ceci:

  version ="1.0" ? > <? Xml version = "1.0"?>
 > <Doc>
     > > Assemblée <
         > Microsoft.Windows.Controls </ name > > Nom Microsoft.Windows.Controls </ name> <
     > /> Assemblée <
     > membres <>
         name ="T:Microsoft.Windows.Controls.Viewbox" > <Nom de membre = "T: Microsoft.Windows.Controls.Viewbox">
             > > Sommaire <
             Définit le contenu d'un décorateur qui peut s'étirer et de l'échelle d'un seul enfant à
             remplir l'espace disponible.
             > / Summary> <
             > Preview </ QualityBand > <QualityBand> <Aperçu /> QualityBand
         > </ Membre>
         name ="F:Microsoft.Windows.Controls.Viewbox.ChildElementName" > <Nom de membre = "F: Microsoft.Windows.Controls.Viewbox.ChildElementName">
             > > Sommaire <
             Nom de l'élément enfant à défaut Viewbox de modèle.
             > / Summary> <
         > </ Membre>
         name ="M:Microsoft.Windows.Controls.Viewbox.IsValidStretchValue(System.Object)" > <Nom de membre = "M: Microsoft.Windows.Controls.Viewbox.IsValidStretchValue (System.Object)">
             > > Sommaire <
             Vérifiez si la valeur est passée dans l'objet une valeur enum valide Stretch.
             > / Summary> <
             name ="o" > The object typed value to be checked. </ param > param name <= "o"> L'objet saisi de la valeur à être vérifiée. </ param>
             > True if o is a valid Stretch enum value, false o/w. </ returns > <> Renvoie Vrai si o est un enum valeur Stretch valide, fausse o <w. / / returns>
         > </ Membre>
         name ="P:Microsoft.Windows.Controls.Viewbox.Child" > <Nom de membre = "P: Microsoft.Windows.Controls.Viewbox.Child">
             > > Sommaire <
             Obtient ou définit l'élément enfant unique d'un Viewbox.
             > / Summary> <
         > </ Membre>
     > </ Membres>
 > </ Doc> 

L'attribut name de chaque élément <member> suit le schéma:

  • "T: Microsoft.Windows.Controls.Viewbox": "T:" indique que cela est un type, suivie par le nom complet du type de;
  • "F: Microsoft.Windows.Controls.Viewbox.ChildElementName": "F:" indique qu'il s'agit d'un champ, suivi du nom complet du champ;
  • "M: Microsoft.Windows.Controls.Viewbox.IsValidStretchValue (System.Object)": "M:" indique qu'il s'agit d'une méthode, suivi du nom complet de la méthode et des paramètres;
  • "P: Microsoft.Windows.Controls.Viewbox.Child": "P" indique que cela est une propriété, suivie par le nom complet de la propriété;

Liens projet Control.Design au dossier Microsoft.Windows.Controls.XML comme ressource incorporée:

  • Microsoft.Windows.Controls.XML comme ressource incorporée
  • Controls.Design.csproj:

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

méthode AddDescriptions analyse le fichier XML intégré et génère DescriptionAttribute pour les classes de contrôle public et de leurs propriétés publiques:

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

AddAttributes est habituellement substituée dans Metadata.cs fichier à ajouter un ToolboxBrowsableAttribute (false) attribut personnalisé pour les classes de contrôle qui ne devrait pas apparaître dans boîte à outils d'un concepteur:

  • si la classe de contrôle doit être caché à tous les designers, ajouter le ToolboxBrowsableAttribute (false) attribut personnalisé au projet Xxx.Design;
  • si elle doit être caché de Visual Studio uniquement, ajoutez l'attribut personnalisé au projet Xxx.VisualStudio.Design;
  • si elle doit être caché Expression Blend uniquement, ajoutez l'attribut personnalisé au projet Xxx.Expression.Design;

Ci-dessous est la mise en œuvre dans AddAttributes Metadata.cs du projet Controls.VisualStudio.Design:

  / / / <summary>
 / / / Fournir un lieu d'ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder.
 / / / / Summary> <
 / / <param Name="builder"> / Le tableau constructeur attribut d'assembly. / Param> <
 protected override void AddAttributes (constructeur AttributeTableBuilder)
 (
     ToolboxBrowsableAttribute( false ))); builder.AddCallback (typeof (TreeViewItem), b => b.AddCustomAttributes (nouveau ToolboxBrowsableAttribute (false)));
 ) 
AddTables

Pour ajouter d'autres attributs que ToolboxBrowsableAttribute (fausse) d'un type, ajouter un fichier comme XxxMetadata.cs ViewboxMetadata.cs ci-dessous pour la conception du projet le cas:

ViewboxMetadata.cs:

  / / (C) Copyright Microsoft Corporation.
 / / Cette source est soumis à la Microsoft Public License (Ms-PL).
 / / S'il vous plaît voir http://go.microsoft.com/fwlink/?LinkID=131993 pour plus de détails.
 / / Tous les autres droits réservés.

 using System.ComponentModel;
 utilisant Microsoft.Windows.Controls.Design.Common;
 utilisant Microsoft.Windows.Design.Metadata;

 namespace Microsoft.Windows.Controls.Design
 (
     / / / <summary>
     / / / Pour vous inscrire métadonnées en temps de conception pour Viewbox.
     / / / / Summary> <
     classe interne ViewboxMetadata: AttributeTableBuilder
     (
         / / / <summary>
         / / / Pour vous inscrire métadonnées en temps de conception pour Viewbox.
         / / / / Summary> <
         ViewboxMetadata public ()
             : Base ()
         (
             AddCallback (
                 typeof (Viewbox),
                 b =>
                 (
                     )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.BorderThickness), nouvelle BrowsableAttribute (false));
                     )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.BorderBrush), nouvelle BrowsableAttribute (false));
                     )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Background), nouvelle BrowsableAttribute (false));
                     )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Foreground), nouvelle BrowsableAttribute (false));

                     b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Child), nouvelle CategoryAttribute (Properties.Resources.CommonProperties));
                     b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Stretch), nouvelle CategoryAttribute (Properties.Resources.CommonProperties));
                     b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.StretchDirection), nouvelle CategoryAttribute (Properties.Resources.CommonProperties));
                 ));
         )
     )
 ) 
  • Il est recommandé de suivre la convention de nommage ici. Prenez Viewbox par exemple, le nom du fichier est ViewboxMetadata.cs, et le nom de classe est ViewboxMetadata.
  • La classe doit hériter de métadonnées AttributeTableBuilder.
  • Vous pouvez ajouter des attributs personnalisés dans le constructeur de la classe de métadonnées:
    • Vous pouvez utiliser le rappel du modèle (comme dans ViewboxMetada.cs ci-dessus) ou le modèle direct. Le modèle de rappel est censé être plus efficace.
      • Par exemple modèle direct:

        AddCustomAttributes (

        typeof (Viewbox), / / type

        "EpaisseurBordure", / nom de la propriété /

        nouvel attribut [] (new BrowsableAttribute (false))); / / tableau d'attributs personnalisés

    • Pour fournir le paramètre nom de la propriété d'appeler AddCustomAttribute, vous pouvez soit utiliser la méthode Extensions.GetMemberName () comme dans ViewboxMetadata.cs (discuterons un peu plus tard dans le post) pour obtenir le nom de la propriété d'une façon sécuritaire de type, ou de fournir des le nom de la propriété directement en tant que chaîne comme "epaisseurBordure" ci-dessus dans la mise en œuvre du modèle direct.

Le AddTables (constructeur AttributeTableBuilder) méthode:

  • énumère tous les sous-classes de AttributeTableBuilder à l'Assemblée d'exécution
  • crée une instance de chaque sous-classe AttributeTableBuilder trouvés:

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

  • Ajouter la table des attributs de la classe trouvée à ce constructeur:

    builder.AddTable (atb.CreateTable ());

Metadata.cs

Metadata.cs implémente la classe MetadataRegistration, qui hérite de la classe MetadataRegistrationBase mis en œuvre dans MetadataBase.cs. Il met également en œuvre IRegisterMetadata interface.

Metadata.cs:

  / / (C) Copyright Microsoft Corporation.
 / / Cette source est soumis à la Microsoft Public License (Ms-PL).
 / / S'il vous plaît voir http://go.microsoft.com/fwlink/?LinkID=131993 pour plus de détails.
 / / Tous les autres droits réservés.

 using System.Reflection;
 utilisant Microsoft.Windows.Controls.Design.Common;
 utilisant Microsoft.Windows.Design.Metadata;

 namespace Microsoft.Windows.Controls.Design
 (
     / / / <summary>
     / / / Classe MetadataRegistration.
     / / / / Summary> <
     public class MetadataRegistration: MetadataRegistrationBase, IRegisterMetadata
     (
         / / / <summary>
         / / / Temps de conception de métadonnées de classe d'immatriculation.
         / / / / Summary> <
         MetadataRegistration public ()
             : 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>
         / / / Emprunté à System.Windows.Controls.Toolbox.Design.MetadataRegistration:
         / / / Utiliser un drapeau statique pour garantir que les métadonnées est inscrit un seul.
         / / / / Summary> <
         private static bool _initialized;

         / / / <summary>
         / / / Appelé par les outils pour enregistrer les métadonnées moment du design.
         / / / / Summary> <
         public void Register ()
         (
             if (! _initialized)
             (
                 MetadataStore.AddAttributeTable (BuildAttributeTable ());
                 _initialized = true;
             )
         )

         / / / <summary>
         / / / Fournir un lieu d'ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder.
         / / / / Summary> <
         / / <param Name="builder"> / Le tableau constructeur attribut d'assembly. / Param> <
         protected override void AddAttributes (constructeur AttributeTableBuilder)
         (
         )
     )
 ) 

Let's discuter certaines de ses méthodes clés:

MetadataRegistration

Ce constructeur initialise deux domaines clés:

  • XmlResourceName: nom de la ressource de la documentation embarquée fichier XML, utilisé par la méthode MetadataRegistrationBase.AddDescriptions.
  • AssemblyFullName: nom complet de l'Assemblée moment de l'exécution de cette assemblée moment de la conception est pour.

Vous avez besoin de remplacer le type Viewbox avec votre propre classe si vous utilisez Metadata.cs dans votre projet de conception propre.

S'inscrire

C'est la seule méthode de IRegisterMetadata interface. Il ajoute la table des attributs personnalisés, compilés à partir de AddDescripions, AddAttributes et méthodes décrites ci-dessus AddTables, pour stocker les métadonnées concepteur:

MetadataStore.AddAttributeTable (BuildAttributeTable ());

Extensions.cs

Ce fichier contient la mise en œuvre de l'extension méthode GetMemberName <T> (Expression <Func <T, object>> expr) qui est utilisé pour obtenir le nom d'un membre d'un type de compilation vérifier de temps et IntelliSense:

méthode d'extension GetMemberName

L'idée a été proposée par Jafar Husain (voir son blog post symboles en C # 3.0 ), puis amélioré par Justin Angel . Il est un grand tour pour éviter les fautes de frappe, mais l'inconvénient est qu'il tire dans les références Silverlight et des assemblées dans une pure autrement. NET. Voici le source complet:

Extensions.cs:

  / / (C) Copyright Microsoft Corporation.
 / / Cette source est soumis à la Microsoft Public License (Ms-PL).
 / / S'il vous plaît voir http://go.microsoft.com/fwlink/?LinkID=131993 pour plus de détails.
 / / Tous les autres droits réservés.

 using System;
 utilisant System.Linq.Expressions;

 namespace Microsoft.Windows.Controls.Design.Common
 (
     / / / <summary>
     / / / Cet ensemble de méthodes d'extension interne de fournir des solutions générales et
     / / / Utilitaires dans un assez petit nombre pour ne pas justifier une extension dédiée
     / / / Méthodes de classe.
     / / / / Summary> <
     Extensions internes classe statique
     (
         / / / <summary>
         / / / Méthode d'assistance pour obtenir le nom des membres de la compilation de vérification à temps pour éviter typo.
         / / / / Summary> <
         / / / <typeparam Name="T"> Le contenant la catégorie de membre dont le nom est récupéré. </> Typeparam
         / / <param Name="expr"> / L'expression lambda généralement sous la forme de O => o.member. / Param> <
         / / / <returns> Le nom de la propriété. </ Returns>
         >> expr) public static string GetMemberName <T> (Expression <Func <T, object>> expr)
         (
             Expression corporelle = ((LambdaExpression) expr). Conseil;
             memberExpression MemberExpression = corps MemberExpression;
             ) if (memberExpression == null)
             (
                 memberExpression = (MemberExpression) ((UnaryExpression) du corps). opérande;
             )
             memberExpression.Member.Name retour;
         )
     )
 ) 

Conclusion

Ce message décrit la mise en œuvre des caractéristiques de la conception dans le Décembre 2008 Communiqué de Silverlight Toolkit , et mis en place un cadre simple pour la mise en œuvre caractéristique de la conception des contrôles Silverlight. Vous pouvez modéliser la mise en oeuvre et de réutiliser le cadre de vos propres projets. Le cadre est encore très primitive, en soutenant l'enregistrement de métadonnées uniquement, car c'est tout ce que Blend supporte pour l'instant. Je vais étudier l'amélioration du cadre et des caractéristiques de la conception pour Silverlight Toolkit, comme l'ajout en ligne personnalisé / étendu / éditeurs de dialogue, les données de la conception, de la conception que les comportements etc

Comme je l'ai indiqué dans les précédents post Temps caractéristiques de conception Silverlight Toolkit , les expériences de la conception des contrôles sont très importants. Il améliore non seulement l'expérience et la productivité des développeurs qui utilisent ces contrôles avec des fonctionnalités temps daigne, mais améliore également l'expérience des utilisateurs finaux, puisque les demandes de plus en plus de donner aux utilisateurs plus de souplesse dans la personnalisation de l'interface utilisateur, comme modifier la présentation en faisant glisser-déplacer des contrôles , ou la modification des paramètres d'un contrôle, tout comme dans un concepteur, sauf qu'il est au moment de l'exécution.

Share and Enjoy:

  • Print
  • email
  • RSS
  • Twitter
  • TwitThis
  • del.icio.us
  • LinkedIn
  • Technorati
  • Facebook
  • Google Bookmarks
  • Live
  • MySpace
  • QQ书签