Поделиться через


Практическое руководство. Расширение конструктора доменного языка

Это можно сделать расширения конструктора, используемые для изменения определения DSL.Введите расширения, то можно сделать, чтобы включить добавление команды меню, добавляя обработчики перетаскивания и дважды щелкнуть жесты и правила, которые активированы, если указанные типы значений или связей.Расширения можно упаковать как расширение интеграции Visual Studio (VSIX) и распределять другим пользователям.

Образец закодируйте и дополнительные сведения об этой функции см. в разделе Visual Studio Визуализация и моделирование веб-сайте пакета SDK (VMSDK).

Настройка решения

Настройте проект, содержащий код расширения и проект VSIX, который экспортирует проект.Решение может содержать другие проекты, которые включены в один и тот же VSIX.

Создание решения расширения конструктор DSL

  1. Создайте новый проект с помощью шаблона проекта библиотеки классов.В диалоговом окне Создать проект щелкните *** Visual C# *** а затем в среднем нажмите кнопку Библиотека классов окна.

    Этот проект будет содержать код собственных расширений.

  2. Создайте новый проект с помощью шаблона проекта VSIX.В диалоговом окне Создать проект разверните *** Visual C# *** нажмите кнопку Расширение среды, а затем в среднем окне выберите Проект VSIX.

    Выберите Добавить в решение.

    Открытые Source.extension.vsixmanifest в редакторе манифеста VSIX.

  3. По содержимому поля, щелкните Добавление содержимого.

  4. В диалоговом окне Добавление содержимого, установите *** Выберите тип содержимого *** к *** компонент MEF *** и набор Проект в проект библиотеки классов.

  5. Щелкните *** Выберите выпуски *** и убедитесь, что *** Visual Studio Ultimate *** проверяется.

  6. Убедитесь, что проект VSIX автозагружаемый проект решения.

  7. В проекте библиотеки классов добавьте ссылки на следующие сборки:

    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

Тестирование и развертывание

Тестирование все расширения в этом разделе, построение и запуск решение.Откроется экспериментальный экземпляр Visual Studio.В этом случае откройте решение DSL.Правка схема DslDefinition.Расширения функциональности расширения можно отобразить.

Развертывание расширений к главному Visual Studio и на других компьютерах, выполните следующие действия:

  1. Найдите файл установки VSIX в проекте VSIX в каталоге bin \ * \ *.vsix

  2. Скопируйте этот файл на целевой компьютер, а затем в проводнике windows (или обозревателе файла) дважды щелкните его.

    Диспетчер расширений Visual Studio открывает для подтверждения того, что расширение было установленно.

Чтобы удалить модуль, выполните следующие действия:

  1. в Visual Studio, в меню Сервис, нажмите кнопку *** Диспетчер расширений ***.

  2. Выберите расширение и удалите его.

Добавление команда контекстного меню

Чтобы сделать команда контекстного меню отображаться в области конструктора DSL либо в окне обозревателя DSL, создайте класс походя следующее.

Класс должен реализовывать ICommandExtension и должен иметь атрибут 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"; }
    }
  }
}

Обработка жесты мыши

Код напоминает код команды меню.

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

Отклик на изменения значений

Этому обработчику модели домена будет работать правильно.Мы обеспечиваем простую модель домена.

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

В следующем коде реализуется простой моделью.Создайте новый идентификатор GUID, чтобы заменить местозаполнитель.

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

    }
}