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


Расширение доменного языка с помощью MEF

Можно exntend свой доменный язык (DSL) с помощью управляемой расширяемости .NET Framework (платформа MEF).Пользователь или другие разработчики будут записи расширения для DSL, не изменяя определение и идентификатор программы DSL.Такие расширения включают в себя команды меню, обработчики перетаскивания и проверку.Пользователи смогут устанавливать пользовательский DSL, а затем при необходимости устанавливают расширения для него.

Кроме того, при включении MEF в вашем DSL может оказаться более удобным написать самостоятельно некоторые функции компонента DSL, даже если все они создаются вместе с DSL.

Дополнительные сведения о MEF см. в разделе Managed Extensibility Framework (MEF).

Включить пользовательский DSL, который будет расширение MEF

  1. Создайте новую папку с именем MefExtension in DslPackage этот проект.Добавьте в него следующие файлы:

    Имя файла

    Содержимое файла

    CommandExtensionVSCT.tt

    Важное примечаниеВажно
    Задайте для идентификатора GUID в этом файле, чтобы быть такими же, как и идентификатор GUID CommandSetId, указанное в DslPackage \ GeneratedCode \ Constants.tt
    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#
    // CmdSet Guid must be defined before master template is included
    // This Guid must be kept synchronized with the CommandSetId Guid in Constants.tt
    Guid guidCmdSet = new Guid ("00000000-0000-0000-0000-000000000000");
    string menuidCommandsExtensionBaseId="0x4000";
    #>
    <#@ include file="DslPackage\CommandExtensionVSCT.tt" #>

    CommandExtensionRegistrar.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\CommandExtensionRegistrar.tt" #>

    ValidationExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\ValidationExtensionEnablement.tt" #>

    ValidationExtensionRegistrar.tt

    Если добавить этот файл необходимо включить проверку своего DSL с помощью как минимум один из параметров в пределах Редактор \ проверка в обозревателе DSL.

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\ValidationExtensionRegistrar.tt" #>

    PackageExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\PackageExtensionEnablement.tt" #>
  2. Создайте новую папку с именем MefExtension in Dsl этот проект.Добавьте в него следующие файлы:

    Имя файла

    Содержимое

    DesignerExtensionMetaDataAttribute.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\DesignerExtensionMetadataAttribute.tt" #>

    GestureExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\GestureExtensionEnablement.tt" #>

    GestureExtensionController.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\GestureExtensionController.tt" #>
  3. Добавьте следующую линия к существующему файлу, который называется DslPackage\Commands.vsct.

    <Include href="MefExtension\CommandExtensionVSCT.vsct"/>
    

    Вставить линию после существовать <Include> директива.

  4. Откройте DslDefinition.dsl.

  5. Выберите в обозревателе DSL Редактор \ проверка.

  6. В окне свойства убедитесь, что хотя бы одно из свойств с именем Использует… существует true.

  7. На панели инструментов обозревателя решений щелкните Преобразовать все шаблоны.

    Дочерние файлы появляются под каждым из файлов, добавленных.

  8. Постройте и запустите решение, чтобы убедиться, что оно все еще работает.

Теперь пользовательский DSL MEF-разрешенн.Можно писать команды меню, обработчиков жестов и ограничения проверки как расширения MEF.Можно написать эти расширения в решении DSL вместе с другим пользовательским кодом.Кроме того или другие разработчики могут написать отдельные Visual Studio Модули, которые расширяют его DSL.

Создание расширения для MEF-разрешенного DSL

Если имеется доступ к MEF-разрешенному DSL, созданный самостоятельно или кто-то другой, то можно написать расширения для него.Расширения можно использовать для добавления команды меню, обработчиков жестов или ограничения проверки.Чтобы разработать эти расширения используется a Visual Studio Решения расширения (VSIX).Решение содержит 2 частей: проект библиотеки классов, построения сборки кода, а проект VSIX, что пакеты сборки.

Создать расширение VSIX DSL

  1. Создайте новый проект библиотеки классов.Для этого в Создать проект диалоговое окно открывается Visual Basic OR Visual c# затем выберите Библиотека классов.

  2. В проекте библиотеки классов необходимо добавить ссылку на сборку DSL.

    • Эту сборку обычно имеет имя, под которым завершается с ". Dsl.dll".

    • Если имеется доступ к проекту DSL, можно найти файл сборки в каталоге Dsl\bin\*

    • Если имеется доступ к файлу DSL VSIX, можно найти сборку, изменяя расширение имени файла zip VSIX в "".Распаковать zip-файл.

  3. Добавьте ссылки на следующие сборки .NET.

    • Microsoft.VisualStudio.Modeling.Sdk.11.0.dll

    • Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0.dll

    • Microsoft.VisualStudio.Modeling.Sdk.Shell.11.0.dll

    • System.ComponentModel.Composition.dll

    • System.Windows.Forms.dll

  4. Создайте проект VSIX в том же решении.Для этого в Создать проект разверните диалоговое окно Visual Basic OR **Visual c#**щелкните Расширение среды, а затем выберите проект VSIX.

  5. В обозревателе решений щелкните правой кнопкой мыши проект и затем выберите VSIX Назначить запускаемым проектом.

  6. В новом проекте, открытие source.extension.vsixmanifest.

  7. Щелкните Добавить содержимое.В диалоговом окне установка Тип контента В компонент MEFи Исходный проект в проект библиотеки классов.

  8. Добавьте ссылки VSIX в DSL.

    1. IN source.extension.vsixmanifestщелкните Добавление ссылки

    2. В диалоговом окне нажмите кнопку Добавить полезные данные затем найдите файл VSIX DSL.Файл VSIX, встраивается в решении DSL, in DslPackage\bin\*.

      Это позволяет пользователям устанавливать DSL и расширение одновременно.Если пользователь уже устанавливал DSL, то только расширение устанавливается.

  9. Просмотр и обновление другие поля source.extension.vsixmanifest.Нажать Выберите выпуски и убедитесь, что выбран правильный Visual Studio выпуски заданы.

  10. Добавьте код к проекту библиотеки классов.Используйте примеры в следующем разделе практическое руководство.

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

  11. Чтобы тестирование расширения, нажмите клавишу F5.В экспериментальном экземпляре Visual Studioсоздайте или откройте файл примера DSL.

Расширения MEF записи для DSLs

Можно написать расширения в проекте кода сборки отдельную решения расширения DSL.Можно также использовать MEF в проекте DslPackage, как удобный способ командам записи, жесты и код проверки как часть DSL.

Ff972471.collapse_all(ru-ru,VS.110).gifКоманды меню

Чтобы написать команду меню, определите класс, реализующий ICommandExtension и префикс класс с атрибут, который определен в вашем DSL, YourDslCommandExtension.Можно создать несколько классов команд меню.

QueryStatus() вызывается, когда пользователь щелкнул правой кнопкой мыши схему.Она должна проверить текущее выделение и набор command.Enabled указать, когда команда применимо.

using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl; // My DSL
using Company.MyDsl.ExtensionEnablement; // My DSL
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; // IVsSelectionContext
using Microsoft.VisualStudio.Modeling.ExtensionEnablement; // ICommandExtension

namespace MyMefExtension
{
  // Defined in Dsl\MefExtension\DesignerExtensionMetaDataAttribute.cs:
  [MyDslCommandExtension] 
  public class MyCommandClass : ICommandExtension
  { 
    /// <summary>
    /// Provides access to current document and selection.
    /// </summary>
    [Import]
    IVsSelectionContext SelectionContext { get; set; }

    /// <summary>
    /// Called when the user selects this command.
    /// </summary>
    /// <param name="command"></param>
    public void Execute(IMenuCommand command)
    {
      // Transaction is required if you want to update elements.
      using (Transaction t = SelectionContext.CurrentStore
              .TransactionManager.BeginTransaction("fix names"))
      {
        foreach (ExampleShape shape in SelectionContext.CurrentSelection)
        {
          ExampleElement element = shape.ModelElement as ExampleElement;
          element.Name = element.Name + " !";
        }
        t.Commit();
      }
    }

    /// <summary>
    /// Called when the user right-clicks the diagram.
    /// Determines whether the command should appear.
    /// This method should set command.Enabled and command.Visible.
    /// </summary>
    /// <param name="command"></param>
    public void QueryStatus(IMenuCommand command)
    {
      command.Enabled =
        command.Visible = (SelectionContext.CurrentSelection.OfType<ExampleShape>().Count() > 0);
    }

    /// <summary>
    /// Called when the user right-clicks the diagram.
    /// Determines the text of the command in the menu.
    /// </summary>
    public string Text
    {
      get { return "My menu command"; }
    }
  }
}

Ff972471.collapse_all(ru-ru,VS.110).gifОбработчиков жестов

Обработчик жестов может работать с объектами перетащенные на схему из любого места внутри, либо снаружи Visual Studio.В следующем примере позволяет пользователям перетаскивать файлы из обозревателя на схему.Он создает элементы, содержащие имена файлов.

Можно написать обработчики, чтобы работать с операцией от других моделей DSL и моделей UML.Дополнительные сведения см. в разделе Практическое руководство. Добавление обработчика перетаскивания.

using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; 
using Microsoft.VisualStudio.Modeling.ExtensionEnablement; 

namespace MefExtension
{
  [MyDslGestureExtension]
  class MyGestureExtension : IGestureExtension
  {
    public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
    {
      System.Windows.Forms.MessageBox.Show("double click!");
    }
    
    /// <summary>
    /// Called when the user drags anything over the diagram.
    /// Return true if the dragged object can be dropped on the current target.
    /// </summary>
    /// <param name="targetMergeElement">The shape or diagram that the mouse is currently over</param>
    /// <param name="diagramDragEventArgs">Data about the dragged element.</param>
    /// <returns></returns>
    public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
    {
      // This handler only allows items to be dropped onto the diagram:
      return targetMergeElement is MefDsl2Diagram &&
      // And only accepts files dragged from Windows Explorer:
        diagramDragEventArgs.Data.GetFormats().Contains("FileNameW");
    }


    /// <summary>
    /// Called when the user drops an item onto the diagram.
    /// </summary>
    /// <param name="targetDropElement"></param>
    /// <param name="diagramDragEventArgs"></param>
    public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
    {
      MefDsl2Diagram diagram = targetDropElement as MefDsl2Diagram;
      if (diagram == null) return;

      // This handler only accepts files dragged from Windows Explorer:
      string[] draggedFileNames = diagramDragEventArgs.Data.GetData("FileNameW") as string[];
      if (draggedFileNames == null || draggedFileNames.Length == 0) return; 

      using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("file names"))
      {
        // Create an element to represent each file:
        foreach (string fileName in draggedFileNames)
        {
          ExampleElement element = new ExampleElement(diagram.ModelElement.Partition);
          element.Name = fileName;

          // This method of adding the new element allows the position
          // of the shape to be specified:          
          ElementGroup group = new ElementGroup(element);
          diagram.ElementOperations.MergeElementGroupPrototype(
            diagram, group.CreatePrototype(), PointD.ToPointF(diagramDragEventArgs.MousePosition));
        }
        t.Commit();
      }
    }
  }
}

Ff972471.collapse_all(ru-ru,VS.110).gifОграничения проверки

Методы проверки помечены ValidationExtension атрибут, который создается DSL, а также by ValidationMethodAttribute.Метод может использоваться в любой класс, который не помечен атрибутом.

Дополнительные сведения см. в разделе Проверка в доменных языках.

using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.Validation;

namespace MefExtension
{
  class MyValidationExtension // Can be any class.
  {
    // SAMPLE VALIDATION METHOD.
    // All validation methods have the following attributes.

    // Specific to the extended DSL:
    [MyDslValidationExtension] 

    // Determines when validation is applied:
    [ValidationMethod(
       ValidationCategories.Save
     | ValidationCategories.Open
     | ValidationCategories.Menu)]
    
    /// <summary>
    /// When validation is executed, this method is invoked
    /// for every element in the model that is an instance
    /// of the second parameter type.
    /// </summary>
    /// <param name="context">For reporting errors</param>
    /// <param name="elementToValidate"></param>
    private void ValidateClassNames
      (ValidationContext context,
       // Type determines to what elements this will be applied:
       ExampleElement elementToValidate)
    { 
      // Write code here to test values and links.
      if (elementToValidate.Name.IndexOf(' ') >= 0)
      {
        // Log any unacceptable values:
        context.LogError(
          // Description:
          "Name must not contain spaces" 
          // Error code unique to this type of error:
          , "MyDsl001" 
          // Element to highlight when user double-clicks error:
          , elementToValidate); 
} } } }

См. также

Основные понятия

Managed Extensibility Framework (MEF)

Практическое руководство. Добавление обработчика перетаскивания

Проверка в доменных языках

Другие ресурсы

развертывание VSIX