Mise en œuvre Feature Time Design dans Silverlight Toolkit
Présentation
C'est le deuxième poste de mon temps Silverlight Caractéristiques de la série Design. Le premier message Fonctions Time Design dans Silverlight Toolkit a montré les caractéristiques du temps de conception du Silverlight Toolkit contrôles. Ce post explique comment il est mis en œuvre. Espérons que ce message peut vous aider en expliquant notre code source, montrant comment implémenter des fonctionnalités temps de conception pour Silverlight, et en fournissant un cadre et des lecteurs de code source peut utiliser directement dans leurs propres projets.
Aperçu
Télécharger "Silverlight Toolkit - Binaires, échantillons, documentation, tests unitaires et sources» de Décembre 2008 Communiqué , SourceSilverlight.Controls.sln ouvert dans Visual Studio, et nous verrons qu'il ya 12 projets de design sous dossier de la solution de conception, trois pour chaque contrôle assemblage.
Prenez Contrôles de projet par exemple, il ya trois projets de conception:
- Controls.Design: construit Windows.Controls.Design.dll, qui contient le temps de caractéristiques de conception partagée par Visual Studio et Expression Blend.
- Controls.Expression.Design: Windows.Controls.Expression.Design.dll construit, qui contient des fonctions de temps de conception pour Expression Blend seulement.
- Controls.VisualStudio.Design: Windows.Controls.VisualStudio.Design.dll construit, qui contient des fonctions de temps de conception pour Visual Studio uniquement.
Il ya aussi un dossier Design.Common qui contient deux fichiers: Extensions.cs et MetadataBase.cs, qui sont partagées par tous les projets de conception.
Il est fortement recommandé que vous lisiez Justin Angel blog post Silverlight extensibilité moment du design : il fournit une bonne base / aperçu des informations sur l'extensibilité Silverlight temps de conception, sur lequel la mise en œuvre ci-dessous est basée.
Projet
Tous les 12 projets de design suivent le schéma de mise en œuvre même, donc je vais juste utiliser Control.Design projet pour leur expliquer tous.
Charge Silverlight.Controls.sln dans le répertoire source dans Visual Studio pour la première fois, nous allons voir l'écran comme ci-dessous:
- Controls.Design a une dépendance de projet sur le projet de Contrôles. Cette dépendance assure que le projet Controls est construit d'abord, et Controls.Design a une référence à l'assemblage Microsoft.Windows.Controls construite par le projet Controls. Un assemblage de temps de conception fait toujours référence à l'assemblée de l'exécution qu'il fournit des fonctionnalités de conception pour le temps.
- Controls.Design références Microsoft.Windows.Design & Microsoft.Windows.Design.Extensibility assemblées, qui sont tous deux sous PublicAssemblies% répertoire% DevEnvDir (C: Program FilesMicrosoft visuelle 9.0Common7IDEPublicAssemblies Studio sur mon portable). Un assemblage de temps de conception souvent référence à ces deux assemblées, qui fournissent l'infrastructure d'extensibilité concepteur. Un temps de montage de conception toujours l'assemblage du système de références aussi, qui contient l'espace de noms System.ComponentModel, où la plupart des attributs de métadonnées (comme CategoryAttribute, DescriptionAttribute) sont définies.
- Controls.Design références System.Windows assemblage. 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 projet Windows Class Library, et non pas un projet Silverlight et le Microsoft.Windows.Controls.Design.dll généré est un assemblage de fonctionner sur NET bureau à l'intérieur des designers comme Visual Studio ou Expression Blend, et non pas un assemblage de Silverlight courir à l'intérieur. un navigateur, même si Microsoft.Windows.Controls.Design.dll est l'assemblée le temps de conception pour le lancer Silverlight Microsoft.Windows.Controls.dll Assemblée temps.
- L'assemblage est référencé System.Windows réalité un assemblage de Silverlight (version 2.0.5.0). System.Windows Assemblée ne peut pas être nécessaire à tous les projets de design pour les contrôles Silverlight. Nous en avons besoin ici, surtout à cause de l'<T> GetMemberName (Expression <Func <T, object>> expr) méthode dans Extension.cs que nous allons discuter plus tard dans l'après. Le mélange de. NET et Silverlight références crée toutes sortes de questions intéressantes, comme nous le verrons bientôt.
Ci-dessous capture d'écran montre ildasm les références mixtes pour NET et Silverlight en assemblées Microsoft.Windows.Controls.Design.dll.:
- Ver. 2:0:21024:1838 est le numéro de version de Silverlight Toolkit version 2008 Décembre.
- Ver. 3:5:0:0 est le numéro de version. NET Framework 3.5.
- Ver. 2:0:0:0 est le numéro de version de Silverlight 2.0.
- Lors du premier projet de Controls.Design charge dans Visual Studio, il ya un «System.Windows 'Le composant référencé est introuvable" avertissement à côté de la référence dans la fenêtre de l'assemblage System.Windows projet, et dans la fenêtre Liste d'erreurs aussi. C'est parce que Controls.Design NET est un projet au lieu de Silverlight, et nous ne savons pas où Silverlight est installé (il est sous C:. Programme FilesMicrosoft Silverlight2.0.31005.0 sur mon portable, et sous C: Program Files (x86 ) Microsoft Silverlight2.0.31005.0 sur mon bureau). La solution est d'avoir un événement de pré-construction de commande .. CopySystemWindows.bat que des copies System.Windows.dll de Silverlight installez direction .. Binaries. Donc, une fois que vous avez construit le projet, l'avertissement va disparaître, comme nous le verrons bientôt.
- En dessus de capture d'écran de Visual Studio, il ya un autre signe d'avertissement à côté de la veuve de Microsoft.Windows.Controls.XML fichier de projet, lorsque vous chargez des projets Controls.Design dans Visual Studio pour la première fois. Ce fichier est généré par la construction du projet dépend des contrôles, car dans Propriétés du projet Contrôle de -> onglet Build, l'option "fichier de documentation XML" est cochée, et dispose d'un chemin de ".. Binar
iesMicrosoft.Windows.Controls.XML ". Si vous construisez des projets Controls.Design, l'avertissement va disparaître, 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 design ont ces trois fichiers. Nous allons en discuter plus en détail plus tard.
Construire des projets Controls.Design ou la solution ensemble, nous pouvons voir:
- Tous les projets construits fines avec 0 erreurs et 0 avertissements.
- Les signes d'alerte à côté de System.Windows de référence et le fichier Microsoft.Windows.Controls.XML disparu.
- L'analyse de code du processus de construction prend du temps, et il génère deux avertissements. Le premier, CA0060, est une autre question de l'mixtes. NET et Silverlight et des références de code dans 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 pour SourceBinaries répertoire 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 (c'est à dire, les sous-classes de FrameworkElement) et leurs propriétés publiques de leur "/ / / <summary>" commentaires de documentation XML en code source. (Bonne paye commenter!
) - Pour masquer une classe de contrôle à partir d'un concepteur, ajoutez une ligne comme celle ci-dessous pour la méthode AddAttributes dans le dossier du projet Metadata.cs:
builder.AddCallback (typeof (TreeViewItem), b => b.AddCustomAttributes (ToolboxBrowsableAttribute nouvelle (fausse))); - Pour enregistrer d'autres attributs personnalisés pour une classe de contrôle, ajouter un fichier XxxMetadata.cs 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:
/ / (C) Copyright Microsoft Corporation. / / Cette source est soumis à la licence Microsoft Public (Ms-PL). / / S'il vous plaît voir http://go.microsoft.com/fwlink/?LinkID=131993 pour plus de détails. / / Tous les autres droits 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) { } } } Classe {/ / / <summary> / / / MetadataRegistration. / / / </ Summary> public class MetadataRegistrationBase {/ / / <summary> / / / Construire le temps de conception d'attributs de métadonnées de table. / / / </ Summary> / / / Table <returns> attribut personnalisé </ returns> protégée BuildAttributeTable virtuels AttributeTable () {AttributeTableBuilder builder = new AttributeTableBuilder (); AddDescriptions (constructeur); AddAttributes (constructeur); AddTables (constructeur); builder.CreateTable return ();}. / / / <summary> / / / Trouver tous les sous-classes AttributeTableBuilder dans l'assemblage / / / et ajouter leurs attributs à la table des attributs de montage. / / / </ summary> / / / <param name="builder"> Le tableau des attributs de montage constructeur </ param> [SuppressMessage ("Microsoft.Design", "CA1031: DoNotCatchGeneralExceptionTypes", Justification = "! dll du temps de conception ne devrait pas manquer»)]. privée AddTables static void (AttributeTableBuilder constructeur) {Debug.Assert (constructeur =! null, "AddTables est appelée avec le paramètre null!"); Assemblée asm = Assembly.GetExecutingAssembly (); foreach (Type 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 (faux, de chaîne de format (CultureInfo.InvariantCulture, «Exception dans la méthode de AddTables:. {0} ", e));}}}} / / / <summary> / / / Obtient ou définit le nom de ressource sensible à la casse du fichier XML incorporé / / / </ summary> XmlResourceName chaîne protégée {get;. jeu ;} / / / <summary> / / / Obtient ou définit le FullName d'assemblage de type «assemblée noms qualifiés / / / </ summary> AssemblyFullName chaîne protégée {get;. fixés;} / / / <summary> / / / Créer attribut description du moment de l'exécution de l'Assemblée fichier xml / / / </ summary> / / / <param name="builder"> Le constructeur table de montage attribut </ param> [SuppressMessage ("Microsoft.Design", "CA1031..: DoNotCatchGeneralExceptionTypes ", Justification =" DLL de temps de conception ne doivent pas échouer ")] private void AddDescriptions (AttributeTableBuilder constructeur) {Debug.Assert (constructeur = null,!" AddDescriptions est appelée avec le paramètre null ");.!. si (string IsNullOrEmpty ( XmlResourceName) | | cordes IsNullOrEmpty (AssemblyFullName)) {return;} XDocument xdoc = XDocument.Load (nouveau StreamReader (Assembly.GetExecutingAssembly ().. GetManifestResourceStream (XmlResourceName))); if (xdoc == null) {return;} foreach (membre de XElement xdoc.Descendants ("membre")) {try {string name = (string) member.Attribute ("nom"); bool = istype name.StartsWith ("T:", StringComparison.OrdinalIgnoreCase); if ( istype | | name.StartsWith ("P", StringComparison.OrdinalIgnoreCase)) {int = lastDot name.Length; chaîne de 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))) {chaîne desc = member.Descendants («sommaire») FirstOrDefault () Valeur; desc = desc.Trim ();. desc = chaîne join ("", desc.Split ( new char [] {'', 't', 'n'}, StringSplitOptions.RemoveEmptyEntries)); if (istype) {builder.AddCallback (t, b => b.AddCustomAttributes (DescriptionAttribute nouvelles (desc)));} else {string propName = name.Substring (lastDot + 1); PropertyInfo pi = t.GetProperty (propName); MethodInfo mi; si (pi = null & & (mi = pi.GetSetMethod ()) = null & & mi.IsPublic! ) {builder.AddCallback (t, b => b.AddCustomAttributes (propName, DescriptionAttribute nouvelles (desc)));}}}}} catch (Exception e) {Debug.Assert (faux, de chaîne de format (CultureInfo.InvariantCulture,. "Exception dans la méthode AddDescriptions: {0}", e));}}} / / / <summary> / / / Fournir un endroit pour ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder / / / </ summary> / / /. <param name="builder"> Le constructeur table de montage attribut. </ param> protégée AddAttributes virtual void (AttributeTableBuilder constructeur) {}}}
MetadataBase.cs implémente la classe MetadataRegistrationBase. Discutons quelques méthodes clés de son:
AddDescriptions
Tous les projets menés temps d'assemblage ont "un fichier XML de documentation» cochée, et avec un chemin comme «.. BinariesMicrosoft.Windows.Controls.XML», dans Projet -> Propriétés -> onglet Générer, section de sortie. Vous pouvez aussi trouver le réglage dans csproj fichier comme ci-dessous.:
> ..BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile > <DocumentationFile> .. BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile>
Voici un extrait du Microsoft.Windows.Controls.XML de montrer ce que la documentation générée fichier XML ressemble à:
un décorateur de contenu qui peut s'étirer et de l'échelle d'un seul enfant pour combler le disponible d'élément enfant en défaut 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 le passé en valeur de l'objet est un Étirez valables valeur enum. </ summary> <param name = "o"> La valeur de l'objet saisi à être vérifiée. </ param> <returns> Vrai si o est une valeur valide stretch enum, fausses o / w. </ returns> </ member> <nom de membre = "P: Microsoft.Windows.Controls.Viewbox.Child">. <summary> Obtient ou définit l'élément enfant unique d'un Viewbox </ summary> < / member> </ membres> </ doc>
L'attribut nom de chaque élément <membre> suit le schéma:
- "T: Microsoft.Windows.Controls.Viewbox": "T:" indique que cela est un type, suivie par le nom complet du type;
- «F: Microsoft.Windows.Controls.Viewbox.ChildElementName": "F:" indique que cela est un domaine, suivi par le nom du champ complet;
- "M: Microsoft.Windows.Controls.Viewbox.IsValidStretchValue (System.Object)": "M:" indique que cela est une méthode, suivie par le nom entièrement qualifié de la méthode et les 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 entre le projet Control.Design au fichier Microsoft.Windows.Controls.XML comme une ressource incorporée:
- Controls.Design.csproj:
Include ="..BinariesMicrosoft.Windows.Controls.XML" /> <EmbeddedResource Inclure = ".. BinariesMicrosoft.Windows.Controls.XML" />
Méthode AddDescriptions analyse le fichier XML incorporé 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 (DescriptionAttribute nouvelles (desc))); MetadataBase.cs: 143: builder.AddCallback (t, b => b.AddCustomAttributes (propName, DescriptionAttribute nouvelles (desc)));
AddAttributes
AddAttributes est généralement substituée dans le fichier Metadata.cs d'ajouter un ToolboxBrowsableAttribute (faux) attribut personnalisé pour les classes de contrôle qui ne doit pas apparaître dans la boîte à outils d'un concepteur:
- si la classe de contrôle doit être caché de tous les designers, ajouter le ToolboxBrowsableAttribute (faux) attribut personnalisé au projet Xxx.Design;
- si elle doit être caché de Visual Studio uniquement, ajoutez l'attribut personnalisé à Xxx.VisualStudio.Design projet;
- si elle doit être caché de Expression Blend uniquement, ajoutez l'attribut personnalisé à Xxx.Expression.Design projet;
Ci-dessous est la mise en œuvre de AddAttributes Metadata.cs du projet Controls.VisualStudio.Design:
/ / / <summary> / / / Fournir un endroit pour ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder. / / / </ Summary> / / / <param Name="builder"> Le constructeur table de montage attribut. </ Param> protégée AddAttributes override void (AttributeTableBuilder constructeur) { ToolboxBrowsableAttribute( false ))); builder.AddCallback (typeof (TreeViewItem), b => b.AddCustomAttributes (ToolboxBrowsableAttribute nouvelle (fausse))); }
AddTables
Pour ajouter des attributs autres que ToolboxBrowsableAttribute (faux) pour un type, ajouter un fichier, comme XxxMetadata.cs ViewboxMetadata.cs ci-dessous pour le projet de conception appropriées:
ViewboxMetadata.cs:
/ / (C) Copyright Microsoft Corporation. / / Cette source est soumis à la licence Microsoft Public (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 du temps de conception pour Viewbox. / / / </ Summary> internes de classe ViewboxMetadata: AttributeTableBuilder { / / / <summary> / / / Pour vous inscrire métadonnées du temps de conception pour Viewbox. / / / </ Summary> publique ViewboxMetadata () : Base () { AddCallback ( typeof (Viewbox), b => { )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.BorderThickness>), de nouveaux BrowsableAttribute (false)); )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.BorderBrush>), de nouveaux BrowsableAttribute (false)); )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Background), BrowsableAttribute nouvelle (fausse)); )); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.Foreground>), de nouveaux BrowsableAttribute (false)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Child), CategoryAttribute nouvelles (Properties.Resources.CommonProperties)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x => x.Stretch), CategoryAttribute nouvelles (Properties.Resources.CommonProperties)); b.AddCustomAttributes (Extensions.GetMemberName <Viewbox> (x = x.StretchDirection>), CategoryAttribute nouvelles (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 soit le modèle de retour d'appel (comme dans ViewboxMetada.cs ci-dessus) ou le modèle direct. Le modèle de rappel est censément plus efficace.
- Par exemple modèle direct:
AddCustomAttributes (
typeof (Viewbox), / / type
"LargeurBordure", / / nom de la propriété
nouvel attribut [] {BrowsableAttribute nouvelle (fausse)}); / / tableau d'attributs personnalisés
- Par exemple modèle direct:
- Pour fournir le nom du paramètre de propriété pour appeler AddCustomAttribute, vous pouvez soit utiliser la méthode de Extensions.GetMemberName () comme dans ViewboxMetadata.cs (discutera plus à ce sujet plus tard dans le post) pour obtenir le nom de la propriété d'une manière sûre le type, ou de fournir le nom de propriété directement en tant que chaîne comme "largeurBordure» dans la mise en œuvre du modèle ci-dessus directement.
- Vous pouvez utiliser soit le modèle de retour d'appel (comme dans ViewboxMetada.cs ci-dessus) ou le modèle direct. Le modèle de rappel est censément plus efficace.
Le AddTables (AttributeTableBuilder constructeur) méthode:
- énumère tous les sous-classes de AttributeTableBuilder dans l'assemblage exécution
- crée une instance de chaque sous-classe AttributeTableBuilder trouvés:
AttributeTableBuilder atb = (AttributeTableBuilder) Activator.CreateInstance (t);
- Ajouter la table des attributs de la classe trouve au constructeur:
builder.AddTable (atb.CreateTable ());
Metadata.cs
Metadata.cs œuvre MetadataRegistration classe, 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 licence Microsoft Public (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> / / / MetadataRegistration classe. / / / </ Summary> public class MetadataRegistration: MetadataRegistrationBase, IRegisterMetadata { / / / <summary> / / / Conception de classe d'immatriculation du temps des métadonnées. / / / </ Summary> MetadataRegistration publique () : 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 assurer des métadonnées est enregistré qu'une seule. / / / </ Summary> private static bool _initialized; / / / <summary> / / / Appelé par les outils pour enregistrer les métadonnées de la conception. / / / </ Summary> S'enregistrer public void () { if (! _initialized) { MetadataStore.AddAttributeTable (BuildAttributeTable ()); _initialized = true; } } / / / <summary> / / / Fournir un endroit pour ajouter des attributs personnalisés, sans créer une sous-classe AttributeTableBuilder. / / / </ Summary> / / / <param Name="builder"> Le constructeur table de montage attribut. </ Param> protégée AddAttributes override void (AttributeTableBuilder constructeur) { } } }
Discutons de certaines de ses méthodes principales:
MetadataRegistration
Ce constructeur initialise deux domaines clés:
- XmlResourceName: nom de la ressource du fichier de documentation XML embarqués, utilisés par la méthode MetadataRegistrationBase.AddDescriptions.
- AssemblyFullName: nom complet de l'assemblée de l'exécution de cette assemblée le temps de conception est pour.
Vous avez besoin de remplacer le Viewbox type avec votre propre classe, si vous utilisez Metadata.cs dans votre projet de conception propre.
S'enregistrer
C'est la seule méthode de IRegisterMetadata interface. Il ajoute la table d'attributs personnalisés, construits à partir AddDescripions, AddAttributes & AddTables méthodes décrites ci-dessus, 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 avec un chèque de la compilation et IntelliSense:
L'idée a été initialement proposé par Jafar Husain (voir son blog Symboles de C # 3.0 ), puis amélioré par Justin en ange . C'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 assemblées dans un autre pur. NET. Voici le code source complet:
Extensions.cs:
/ / (C) Copyright Microsoft Corporation. / / Cette source est soumis à la licence Microsoft Public (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; Microsoft.Windows.Controls.Design.Common namespace { / / / <summary> / / / Cet ensemble de méthodes d'extension interne de fournir des solutions générales et / / / Utilitaires dans un petit nombre suffisant pour ne pas justifier une extension dédiée / / / Méthodes de classe. / / / </ Summary> internes des extensions de classe statique { / / / <summary> / / / Helper méthode pour obtenir le nom de membre avec la vérification de la compilation pour éviter typo. / / / </ Summary> / / / <typeparam Name="T"> La classe contenant du membre dont le nom est extrait. </ Typeparam> / / / <param Name="expr"> L'expression lambda généralement sous la forme d'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) Corps; MemberExpression MemberExpression corps = que MemberExpression; ) if (memberExpression == null) { memberExpression = (MemberExpression) ((UnaryExpression) corps) Opérande.; } retour memberExpression.Member.Name; } } }
Conclusion
Ce message décrit la mise en œuvre des fonctionnalités de conception dans le temps de Décembre 2008 Communiqué de Silverlight Toolkit , et introduit un cadre simple pour la mise en œuvre fonction du temps de 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 primitif, soutenant l'inscription uniquement des métadonnées, puisque c'est tout ce mélange supporte pour l'instant. Je vais regarder dans l'amélioration du cadre et les caractéristiques du temps de conception pour Silverlight Toolkit, comme l'ajout d'éditeurs en ligne personnalisée / étendue / dialogue, les données de la conception, le temps de conception que les comportements etc
Comme je le disais dans post précédent Caractéristiques moment du design dans Silverlight Toolkit , les expériences de temps de conception pour les 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, car les applications de plus en plus de donner aux utilisateurs plus de flexibilité dans la personnalisation de l'interface utilisateur, comme changer la disposition en faisant glisser des contrôles de , ou de modifier les paramètres d'un contrôle, tout comme dans un concepteur, sauf qu'il est au moment de l'exécution.








Les commentaires récents