Comment : étendre le concepteur de langage spécifique à un domaine
Vous pouvez créer des extensions au concepteur que vous utilisez pour modifier des définitions DSL. Types d'extensions que vous pouvez effectuer inclure ajouter des commandes de menu, l'ajout des gestionnaires pour les commandes de glisser-déplacer et de double-clic, et règles qui sont déclenchées lorsque des types particuliers de valeurs ou de relations changent. Les extensions peuvent être empaquetées comme une extension d'intégration Visual Studio (VSIX) et être distribuées à d'autres utilisateurs.
Pour l'exemple de code et plus d'informations sur cette fonctionnalité, consultez Visual Visualisation et de modélisation du site Web du Kit de développement logiciel (VMSDK)Studio.
Installation de la solution
Installez un projet qui contient le code de votre extension, et un projet VSIX qui exporte le projet. Votre solution peut contenir d'autres projets intégrés au même projet VSIX.
Pour créer une solution du concepteur d'extension DSL
Créez un projet à l'aide de le modèle de projet Bibliothèque de classes. Dans la boîte de dialogue Nouveau projet , cliquez sur Visual C# puis cliquez sur dans le moyen Bibliothèque de classesde fenêtre.
Ce projet contiendra le code de vos extensions.
Créez un projet à l'aide de le modèle de projet VSIX. Dans la boîte de dialogue Nouveau projet , développez Visual C#, cliquez sur Extensibilité, puis dans la fenêtre centrale projet VSIXsélectionnez.
Sélectionnez Ajouter à la solution.
Source.extension.vsixmanifest s'ouvre dans l'éditeur de manifeste VSIX.
Au-dessus de le champ de contenu, cliquez sur Ajouter du contenu.
Dans la boîte de dialogue Ajouter du contenu , affectez Sélectionnez un type de contenu à Composant MEF, et le jeu Projet à votre projet Bibliothèque de classes.
Cliquez sur sélectionnez les éditions et assurez -vous que Visual Studio ultimate est activée.
Assurez-vous que le projet VSIX est le projet de démarrage de la solution.
Dans le projet de Bibliothèque de classes, ajoutez des références aux assemblys suivants :
Microsoft.VisualStudio.CoreUtility
Microsoft.VisualStudio.Modeling.Sdk.11.0
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0
Microsoft.VisualStudio.Modeling.Sdk.DslDefinition.11.0
Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0
System.ComponentModel.Composition
System.Drawing
System.Drawing.Design
System.Windows.Forms
Test et déploiement
Pour tester les extensions l'une des dans cette rubrique, générez et exécutez la solution. Une instance expérimentale de Visual Studio s'ouvre alors. Dans ce cas, ouvrez une solution DSL. Modifiez le diagramme de DslDefinition. Le comportement d'extension peut être vu.
Pour déployer les extensions de Visual Studioprincipal, et à d'autres ordinateurs, suivez ces étapes :
Recherchez le fichier d'installation VSIX, dans votre projet VSIX dans le dossier bin \ * \ *.vsix
Copiez le fichier sur l'ordinateur cible, puis dans l'Explorateur Windows (ou l'Explorateur de fichiers), double-cliquant dessus.
Le gestionnaire d'extensions d' Visual Studio s'ouvre pour confirmer que l'extension a été installée.
Pour désinstaller l'extension, suivez ces étapes :
dans Visual Studio, dans le menu Outils , cliquez sur gestionnaire d'extensions.
Sélectionnez l'extension et déposez -la.
Ajouter une commande de menu contextuel
Pour créer une commande de menu contextuel apparaître sur l'aire du concepteur DSL ou dans la fenêtre explorateur DSL, écrivez une classe ressemblant à celui-ci.
La classe doit implémenter ICommandExtension et doit avoir l'attribut DslDefinitionModelCommandExtension.
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.DslDefinition;
using Microsoft.VisualStudio.Modeling.DslDefinition.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.DslDesigner;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Command extending the DslDesigner.
/// </summary>
[DslDefinitionModelCommandExtension]
public class MyDslDesignerCommand : ICommandExtension
{
/// <summary>
/// Selection Context for this command
/// </summary>
[Import]
IVsSelectionContext SelectionContext { get; set; }
/// <summary>
/// Is the command visible and active?
/// This is called when the user right-clicks.
/// </summary>
public void QueryStatus(IMenuCommand command)
{
command.Visible = true;
// Is there any selected DomainClasses in the Dsl explorer?
command.Enabled =
SelectionContext.AtLeastOneSelected<DomainClass>();
// Is there any selected ClassShape on the design surface?
command.Enabled |=
(SelectionContext.GetCurrentSelection<ClassShape>()
.Count() > 0);
}
/// <summary>
/// Executes the command
/// </summary>
/// <param name="command">Command initiating this action</param>
public void Execute(IMenuCommand command)
{
...
}
/// <summary>
/// Label for the command
/// </summary>
public string Text
{
get { return "My Command"; }
}
}
}
Mouvements de souris de gestion
Le code est semblable au code de la commande de menu.
[DslDefinitionModelGestureExtension]
class MouseGesturesExtensions : IGestureExtension
{
/// <summary>
/// Double-clicking on a shape representing a Domain model element displays this model element in a dialog box
/// </summary>
/// <param name="targetElement">Shape element on which the user has clicked</param>
/// <param name="diagramPointEventArgs">event args for this double-click</param>
public void OnDoubleClick(ShapeElement targetElement,
DiagramPointEventArgs diagramPointEventArgs)
{
ModelElement modelElement = PresentationElementHelper.
GetDslDefinitionModelElement(targetElement);
if (modelElement != null)
{
MessageBox.Show(string.Format(
"Double clicked on {0}", modelElement.ToString()),
"Model element double-clicked");
}
}
/// <summary>
/// Tells if the DslDesigner can consume the to-be-dropped information
/// </summary>
/// <param name="targetMergeElement">Shape on which we try to drop</param>
/// <param name="diagramDragEventArgs">Drop event</param>
/// <returns><c>true</c> if we can consume the to be dropped data, and <c>false</c> otherwise</returns>
public bool CanDragDrop(ShapeElement targetMergeElement,
DiagramDragEventArgs diagramDragEventArgs)
{
if (diagramDragEventArgs.Data.GetDataPresent(DataFormats.FileDrop))
{
diagramDragEventArgs.Effect = DragDropEffects.Copy;
return true;
}
return false;
}
/// <summary>
/// Processes the drop by displaying the dropped text
/// </summary>
/// <param name="targetMergeElement">Shape on which we dropped</param>
/// <param name="diagramDragEventArgs">Drop event</param>
public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
{
if (diagramDragEventArgs.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] droppedFiles =
diagramDragEventArgs.Data.
GetData(DataFormats.FileDrop) as string[];
MessageBox.Show(string.Format("Dropped text {0}",
string.Join("\r\n", droppedFiles)), "Dropped Text");
}
}
}
Réponse aux modifications de valeur
Ce gestionnaire a besoin d'un modèle de domaine pour fonctionner correctement. Nous fournissons un modèle simple de domaine.
using System.Diagnostics;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.DslDefinition;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Rule firing when the type of a domain model property is changed. The change is displayed
/// in the debugger (Output window of the Visual Studio instance debugging this extension)
/// </summary>
[RuleOn(typeof(PropertyHasType))]
public class DomainPropertyTypeChangedRule : RolePlayerChangeRule
{
/// <summary>
/// Method called when the Type of a Domain Property
/// is changed by the user in a DslDefinition
/// </summary>
/// <param name="e"></param>
public override void RolePlayerChanged(RolePlayerChangedEventArgs e)
{
// We are only interested in the type
if (e.DomainRole.Id == PropertyHasType.TypeDomainRoleId)
{
PropertyHasType relationship =
e.ElementLink as PropertyHasType;
DomainType newType = e.NewRolePlayer as DomainType;
DomainType oldType = e.OldRolePlayer as DomainType;
DomainProperty property = relationship.Property;
// We write about the Type change in the debugguer
Debug.WriteLine(string.Format("The type of the Domain property '{0}' of domain class '{1}' changed from '{2}' to '{3}'",
property.Name,
property.Class.Name,
oldType.GetFullName(false),
newType.GetFullName(false))
} } } );
Le code suivant implémente un modèle simple. Créez un nouveau GUID pour remplacer l'espace réservé.
using System;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.DslDefinition;
namespace Fabrikam.SimpleDslDesignerExtension
{
/// <summary>
/// Simplest possible domain model
/// needed only for extension rules.
/// </summary>
[DomainObjectId(SimpleDomainModelExtension.DomainModelId)]
public class SimpleDomainModelExtension : DomainModel
{
// Id of this domain model extension
// Please replace this with a new GUID:
public const string DomainModelId =
"00000000-0000-0000-0000-000000000000";
/// <summary>
/// Constructor for the domain model extension
/// </summary>
/// <param name="store">Store in which the domain model will be loaded</param>
public SimpleDomainModelExtension(Store store)
: base(store, new Guid(SimpleDomainModelExtension.DomainModelId))
{
}
/// <summary>
/// Rules brought by this domain model extension
/// </summary>
/// <returns></returns>
protected override System.Type[] GetCustomDomainModelTypes()
{
return new Type[] {
typeof(DomainPropertyTypeChangedRule)
};
}
}
/// <summary>
/// Provider for the DomainModelExtension
/// </summary>
[Export(typeof(DomainModelExtensionProvider))] [ProvidesExtensionToDomainModel(typeof(DslDefinitionModelDomainModel))]
public class SimpleDomainModelExtensionProvider
: DomainModelExtensionProvider
{
/// <summary>
/// Extension model type
/// </summary>
public override Type DomainModelType
{
get
{
return typeof(SimpleDomainModelExtension);
}
}
}
}