Freigeben über


Gewusst wie: Erweitern des DSL-Designers

Sie können Erweiterungen am Designer vornehmen, mit dem Sie DSL-Definitionen bearbeiten.Erweiterungstypen, die Sie ausführen können, umfassen das Hinzufügen von Menübefehlen, das Hinzufügen von Handlern für Zieh- und Doppelklickgesten sowie Regeln, die ausgelöst werden, wenn sich bestimmte Typen von Werten oder Beziehungen ändern.Die Erweiterung kann als Visual Studio Integration Extension (VSIX) verpackt und an andere Benutzer verteilt werden.

Beispielcode und weitere Informationen über diese Funktion finden Sie unter Visual Studio Visualisierungs- und Modellierungs-SDK- (VMSDK).

Einrichten der Projektmappe

Richten Sie ein Projekt ein, das den Code der Erweiterung enthält, und ein VSIX-Projekt, das das Projekt exportiert.Die Projektmappe kann andere Projekte enthalten, die in derselben VSIX enthalten sind.

So erstellen Sie eine Erweiterungs-Projektmappe für DSL-Designer

  1. Erstellen Sie ein neues Projekt mithilfe der Projektvorlage "Klassenbibliothek".Klicken Sie im Dialogfeld Neues Projekt auf Visual C#, und klicken Sie dann im mittleren Fenster auf Klassenbibliothek.

    Dieses Projekt enthält den Code der Erweiterungen.

  2. Erstellen Sie mit der VSIX-Projektvorlage ein neues Projekt.Erweitern Sie im Dialogfeld Neues Projekt die Option Visual C#, klicken Sie auf Erweiterungen, und klicken Sie anschließend im mittleren Fenster auf VSIX Project.

    Wählen Sie Hinzufügen aus.

    Source.extension.vsixmanifest wird im VSIX-Manifest-Editor geöffnet.

  3. Klicken Sie über dem Inhaltsfeld auf Inhalt hinzufügen.

  4. Legen Sie im Dialogfeld Inhalt hinzufügenInhaltstyp auswählen zu MEF-Komponente fest, und legen Sie Projekt auf das Klassenbibliotheksprojekt fest.

  5. Klicken Sie auf Editionen auswählen, und stellen Sie sicher, dass Visual Studio Ultimate überprüft wird.

  6. Stellen Sie sicher, dass das VSIX-Projekt das Startprojekt der Projektmappe ist.

  7. Fügen Sie im Klassenbibliotheksprojekt Verweise auf die folgenden Assemblys hinzu:

    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

Tests und Bereitstellung

Um alle Erweiterungen in diesem Thema testen, erstellen Sie die Projektmappe, und führen Sie sie aus.Eine experimentelle Instanz von Visual Studio wird geöffnet.Öffnen Sie in diesem Fall eine DSL-Projektmappe.Bearbeiten Sie das DslDefinition-Diagramm.Das Erweiterungsverhalten ist sichtbar.

Um die Erweiterungen für dem primären Visual Studio und zu anderen Computern bereitzustellen, Führen die folgenden Schritte aus:

  1. Suchen Sie die Datei VSIX-Installation im VSIX-Projekt in * \ Bin \ *.vsix

  2. Kopieren Sie diese Datei auf den Zielcomputer und dann in Windows Explorer (oder im Datei-Explorer), doppelklicken darauf.

    Der Erweiterungs-Manager von Visual Studio wird geöffnet, um zu bestätigen, dass die Erweiterung installiert wurde.

Um die Erweiterung zu deinstallieren, führen Sie folgende Schritte aus:

  1. Klicken Sie in Visual Studio im Menü Extras auf Erweiterungs-Manager.

  2. Wählen Sie die Ausnahme aus, und löschen Sie sie.

Hinzufügen eines Verknüpfungsmenübefehls

Wenn ein Kontextmenübefehl in der Oberfläche des DSL-Designers oder im DSL-Explorer-Fenster angezeigt werden soll, schreiben Sie eine Klasse, die der Folgenden ähnelt.

Die Klasse muss ICommandExtension implementieren und muss das Attribut DslDefinitionModelCommandExtension haben.

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"; }
    }
  }
}

Behandlung von -Mausgesten

Der Code ähnelt dem Code des Menübefehls.

[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");
   }
  }
 }

Reagieren auf Wertänderungen

Dieser Handler benötigt für die ordnungsgemäße Funktionsweise ein Domänenmodell.Wir stellen ein einfaches Domänenmodell bereit.

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))
} }  }  );

Der folgende Code implementiert ein einfaches Modell.Erstellen Sie ein neues GUID, um den Platzhalter zu ersetzen.

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);
            }
        }

    }
}