Практическое руководство. Определение обработчика жестов на схеме моделирования

В Visual Studio Ultimate можно определить команды, которые выполняются, когда пользователь дважды щелкает элементы на UML-схеме или перетаскивает элементы на эту схему.Эти расширения можно упаковать в расширение интеграции Visual Studio (VSIX) и распространить их среди других пользователей Visual Studio Ultimate.

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

Требования

Создание обработчика жестов

Чтобы определить обработчик жестов для конструктора UML, необходимо создать класс, определяющий поведение обработчика жестов, и внедрить этот класс в расширение Visual Studio Integration Extension (VSIX).Расширение VSIX выполняет роль контейнера, позволяющего установить обработчик.Предусмотрено два альтернативных способа определения обработчика жестов.

  • Создайте обработчик жестов в его собственном расширении VSIX с помощью шаблона проекта. Этот метод является более быстрым.Используйте его, если не требуется объединять обработчик с другими типами расширений, такими как расширения проверки, пользовательские элементы панели элементов или команды меню.

  • Создайте отдельный обработчик жестов и проекты VSIX. Этот метод следует использовать, если требуется объединить несколько типов расширений в одном VSIX-файле.Например, если для обработчика жестов требуется, чтобы в модели соблюдались определенные ограничения, обработчик жестов можно внедрить в то же расширение VSIX, что и метод проверки.

Создание обработчика жестов в его собственном расширении VSIX

  1. В диалоговом окне Создать проект в разделе Проекты моделирования выберите Расширение жеста.

  2. Откройте файл .cs в новом проекте и внесите в класс GestureExtension изменения, реализующие обработчик жестов.

    Дополнительные сведения см. в разделе Реализация обработчика жестов.

  3. Проверьте обработчик жестов, нажав клавишу F5.Дополнительные сведения см. в разделе Выполнение обработчика жестов.

  4. Установите обработчик жестов на другой компьютер, скопировав файл bin\*\*.vsix, построенный вашим проектом.Дополнительные сведения см. в разделе Установка обработчика жестов.

Здесь альтернативная процедура:

Создание отдельного проекта библиотеки классов (DLL) для обработчика жестов

  1. Создайте проект библиотеки классов либо в новом, либо в существующем решении Visual Studio.

    1. В меню Файл выберите Создать, Проект.

    2. В разделе Установленные шаблоны выберите Visual C# или Visual Basic, затем в центральном столбце выберите элемент Библиотека классов.

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

    Microsoft.VisualStudio.Modeling.Sdk.11.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

    System.Windows.Forms

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer — требуется только при расширении схем слоев.Дополнительные сведения см. в разделе Расширение схем слоев.

  3. Добавьте файл класса в проект со следующим кодом.

    ПримечаниеПримечание

    Измените пространство имен и имя класса в соответствии с вашими предпочтениями.

    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
    using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Uml.Classes;
    // ADD other UML namespaces if required
    
    namespace MyGestureHandler // CHANGE
    {
      // DELETE any of these attributes if the handler
      // should not work with some types of diagram.
      [ClassDesignerExtension]
      [ActivityDesignerExtension]
      [ComponentDesignerExtension]
      [SequenceDesignerExtension]
      [UseCaseDesignerExtension]
      // [LayerDesignerExtension]
    
      // Gesture handlers must export IGestureExtension:
      [Export(typeof(IGestureExtension))]
      // CHANGE class name
      public class MyGesture1 : IGestureExtension
      {
        [Import]
        public IDiagramContext DiagramContext { get; set; }
    
        /// <summary>
        /// Called when the user double-clicks on the diagram
        /// </summary>
        /// <param name="targetElement"></param>
        /// <param name="diagramPointEventArgs"></param>
        public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target shape, if any. Null if the target is the diagram.
          IShape targetIShape = targetElement.CreateIShape();
    
          // Do something...
        }
    
        /// <summary>
        /// Called repeatedly when the user drags from anywhere on the screen.
        /// Return value should indicate whether a drop here is allowed.
        /// </summary>
        /// <param name="targetMergeElement">References the element to be dropped on.</param>
        /// <param name="diagramDragEventArgs">References the element to be dropped.</param>
        /// <returns></returns>
        public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target element, if any. Null if the target is the diagram.
          IShape targetIShape = targetMergeElement.CreateIShape();
    
          // This example allows drag of any UML elements.
          return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0;
        }
    
    
        /// <summary>
        /// Execute the action to be performed on the drop.
        /// </summary>
        /// <param name="targetDropElement"></param>
        /// <param name="diagramDragEventArgs"></param>
        public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
        }
    
        /// <summary>
        /// Retrieves UML IElements from drag arguments.
        /// Works for drags from UML diagrams.
        /// </summary>
        private IEnumerable<IElement> GetModelElementsFromDragEvent
                (DiagramDragEventArgs dragEvent)
        {
          //ElementGroupPrototype is the container for
          //dragged and copied elements and toolbox items.
          ElementGroupPrototype prototype =
             dragEvent.Data.
             GetData(typeof(ElementGroupPrototype))
                  as ElementGroupPrototype;
          // Locate the originals in the implementation store.
          IElementDirectory implementationDirectory =
             dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
    
          return prototype.ProtoElements.Select(
            prototypeElement =>
            {
              ModelElement element = implementationDirectory
                .FindElement(prototypeElement.ElementId);
              ShapeElement shapeElement = element as ShapeElement;
              if (shapeElement != null)
              {
                // Dragged from a diagram.
                return shapeElement.ModelElement as IElement;
              }
              else
              {
                // Dragged from UML Model Explorer.
                return element as IElement;
              }
            });
        }
    
      }
    }
    

    Дополнительные сведения о реализации методов см. в разделе Реализация обработчика жестов.

Команду меню необходимо добавить в проект VSIX, который выступает контейнером для установки команды.Если необходимо, в тот же проект VSIX можно включить другие компоненты.

Добавление отдельного обработчика жестов в проект VSIX

  1. Эта операция не требуется, если обработчик жестов создан со своим собственным расширением VSIX.

  2. Создайте проект VSIX, если ваше решение еще его не содержит.

    1. В обозревателе решений в контекстном меню решения выберите Добавить, Создать проект.

    2. В разделе Установленные шаблоны разверните узел Visual C# или Visual Basic, а затем выберите пункт Расширение среды.В среднем столбце выберите Проект VSIX.

  3. Сделайте проект VSIX автоматически загружаемым проектом решения.

    • В окне обозревателя решений в контекстном меню проекта VSIX выберите команду Назначить запускаемым проектом.
  4. В source.extension.vsixmanifest, добавьте проект библиотеки классов обработчика жестов в качестве компонента MEF:

    1. На вкладке Метаданные задайте имя VSIX.

    2. На вкладке Цели установки задайте Visual Studio Ultimate и Premium в качестве целевых объектов.

    3. На вкладке Активы выберите Создать и в диалоговом окне установите:

      Тип = Компонент MEF

      Источник = Проект в текущем решении

      Проект = Проект библиотеки классов

Выполнение обработчика жестов

В целях проверки следует запускать обработчик жестов в режиме отладки.

Для проверки обработчика жестов

  1. Нажмите F5 или щелкните в меню Отладка пункт Начать отладку.

    Запустится экспериментальный экземпляр Visual Studio.

    Устранение неполадок. Если новый экземпляр Visual Studio не запускается.

    • Если имеется более одного проекта, убедитесь, что проект VSIX назначен запускаемым проектом решения.

    • В обозревателе решений в контекстном меню запускаемого или единственного проекта выберите команду Свойства.В редакторе свойств проекта перейдите на вкладку Отладка.Проверьте, что строка в поле Запуск внешней программы является полным путем к Visual Studio; обычно она имеет следующий вид:

      C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe

  2. В экспериментальном экземпляре Visual Studio откройте или создайте проект моделирования и откройте или создайте схему моделирования.Используйте схему одного из типов, перечисленных в атрибутах вашего класса обработчика жестов.

  3. Дважды щелкните в любом месте схемы.Обработчик двойного щелчка будет вызван.

  4. Перетащите элемент из обозревателя UML на схему.Обработчик перетаскивания будет вызван.

Устранение неполадок. Если обработчик жестов не работает, убедитесь в следующем:

  • Проект обработчика жестов указан в качестве компонента MEF на вкладке Активы в source.extensions.manifest в проекте VSIX;

  • параметры всех атрибутов Import и Export являются допустимыми;

  • метод CanDragDrop не возвращает значение false;

  • Тип используемой схемы модели (UML-схема классов, схема последовательности и т. д.) перечислен в качестве одного из атрибутов класса обработчика жестов — [ClassDesignerExtension], [SequenceDesignerExtension] и т. д.

  • Для данного типа целевого и переносимого элемента нет встроенной функциональности.

Реализация обработчика жестов

Ee534033.collapse_all(ru-ru,VS.110).gifМетоды обработчика жестов

Класс обработчика жестов реализует и экспортирует тип IGestureExtension.Ниже перечислены методы, которые необходимо определить.

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Чтобы разрешить сброс исходного элемента, на который ссылается dragEvent, на данный целевой объект, возвращаемое значение должно быть равным true.

Этот метод не должен изменять модель.Метод должен работать быстро, поскольку он используется для определения состояния указателя по мере того, как пользователь двигает мышь.

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Обновите модель на основе исходного объекта, на который ссылается dragEvent, и целевого объекта.

Вызывается, когда пользователь отпускает кнопку мыши после перетаскивания.

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target — это фигура, которую дважды щелкнул пользователь.

Можно создать обработчики, которые могут принимать не только UML, но и различные другие элементы, такие как файлы, узлы в представлении классов .NET, узлы в Architecture Explorer и т. д.Пользователь может перетащить любые из этих элементов на UML-схему при условии, что создан метод OnDragDrop, который может декодировать сериализованную форму этих элементов.Методы декодирования различаются в зависимости от типа элемента.

Ниже представлены параметры этих методов.

  • ShapeElement target.Фигура или схема, на которую пользователь перетащил объекты.

    ShapeElement — это класс реализации, лежащий в основе инструментов моделирования UML.Чтобы снизить риск приведения модели и схем UML в несогласованное состояние, рекомендуется не использовать методы этого класса напрямую.Вместо этого нужно создать для элемента программу-оболочку IShape и использовать методы, описанные в разделе Практическое руководство. Отображение модели на схемах.

    • Получение программы-оболочки IShape

      IShape targetIShape = target.CreateIShape(target);
      
    • Получение элемента модели, являющегося целевым объектом операции перетаскивания или двойного щелчка

      IElement target = targetIShape.Element;
      

      Его можно привести к более конкретному типу элементов.

    • Получение хранилища моделей UML, которое содержит модель UML

      IModelStore modelStore = 
        targetIShape.Element.GetModelStore(); 
      
    • Получение доступа к основному приложению и поставщику услуг

      target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
      
  • DiagramDragEventArgs eventArgs.Этот параметр содержит исходный объект операции перетаскивания в сериализованной форме.

    System.Windows.Forms.IDataObject data = eventArgs.Data;  
    

    На схему можно перетаскивать элементы разных видов из разных частей Visual Studio или с рабочего стола Windows.В IDataObject разные типы элементов кодируются по-разному.Инструкции по извлечению элементов см. в документации по соответствующему типу объекта.

    Если исходным объектом является UML-элемент, перетащенный из проводника по моделям UML или с другой UML-схемы, см. раздел Практическое руководство. Получение элементов модели UML из IDataObject.

Ee534033.collapse_all(ru-ru,VS.110).gifСоздание кода методов

Дополнительные сведения о создании кода для чтения и обновления модели см. в разделе Программирование с UML API.

Дополнительные сведения о доступе к сведениям о модели в операции перетаскивания см. в разделе Практическое руководство. Получение элементов модели UML из IDataObject.

Сведения о работе со схемой последовательностей см. в разделе Практическое руководство. Редактирование схем последовательностей с помощью API UML.

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

[Import] public IDiagramContext DiagramContext { get; set; }

Объявление IDiagramContext позволяет создавать код в методах, осуществляющих доступ к схеме, текущему выделению и модели.

IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}

Дополнительные сведения см. в разделе Практическое руководство. Навигация по UML-модели.

Установка и удаление расширения

Расширение Visual Studio можно установить как на своем компьютере, так и на других.

Установка расширения

  1. Найдите на компьютере файл .vsix, который был создан проектом VSIX.

    1. В Обозреватель решений, в контекстном меню проекта VSIX выберите Открыть папку в проводнике Windows.

    2. Найдите файл bin\*\Ваш_проект.vsix

  2. Скопируйте файл .vsix на конечный компьютер, на котором необходимо установить расширение.Это может быть ваш компьютер или любой другой.

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

  3. Откройте файл .vsix на конечном компьютере.

    Visual Studio Extension Installer откроет и установит расширение.

  4. Запустите или перезапустите Visual Studio.

Удаление расширения

  1. В меню Инструменты выберите пункт Диспетчер расширений.

  2. Разверните Установленные расширения.

  3. Выберите расширение и щелкните Удалить.

Иногда не удается загрузить ошибочное расширение. В этом случае создается отчет в окне ошибок, но расширение не отображается в диспетчере расширений.В этом случае расширение можно удалить, удалив файл из

%LocalAppData%\Local\Microsoft\VisualStudio\11.0\Extensions

Пример

В следующем примере кода показано создание линий жизни на схеме последовательностей с использованием частей и портов компонента, перетащенных со схемы компонентов.

Чтобы проверить этот сценарий, нажмите клавишу F5.Откроется экспериментальный экземпляр Visual Studio.Откройте модель UML и создайте компонент на схеме компонентов в этом экземпляре.Добавьте в этот компонент несколько интерфейсов и внутренних частей компонента.Выберите интерфейсы и части.Затем перетащите интерфейсы и части на схему последовательностей.(Перетащите элемент со схемы компонентов вверх на вкладку схемы последовательностей, а затем вниз на собственно схему последовательностей.) Отобразится линия жизни для каждого интерфейса и части.

Дополнительные сведения о связывании взаимодействий со схемами последовательностей см. в разделе Практическое руководство. Редактирование схем последовательностей с помощью API UML.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;

/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
  [Import]
  public IDiagramContext Context { get; set; }

  /// <summary>
  /// Called by the modeling framework when
  /// the user drops something on a target.
  /// </summary>
  /// <param name="target">The target shape or diagram </param>
  /// <param name="dragEvent">The item being dragged</param>
  public void OnDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    ISequenceDiagram diagram = Context.CurrentDiagram
            as ISequenceDiagram;
    IInteraction interaction = diagram.Interaction;
    if (interaction == null)
    {
      // Sequence diagram is empty: create an interaction.
      interaction = diagram.ModelStore.Root.CreateInteraction();
      interaction.Name = Context.CurrentDiagram.Name;
      diagram.Bind(interaction);
    }
    foreach (IConnectableElement connectable in
       GetConnectablesFromDrag(dragEvent))
    {
      ILifeline lifeline = interaction.CreateLifeline();
      lifeline.Represents = connectable;
      lifeline.Name = connectable.Name;
    }
  }

  /// <summary>
  /// Called by the modeling framework to determine whether
  /// the user can drop something on a target.
  /// Must not change anything.
  /// </summary>
  /// <param name="target">The target shape or diagram</param>
  /// <param name="dragEvent">The item being dragged</param>
  /// <returns>true if this item can be dropped on this target</returns>
  public bool CanDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
    return connectables.Count() > 0;
  }

  ///<summary>
  /// Get dragged parts and ports of an IComponent.
  ///</summary>
  private IEnumerable<IConnectableElement>
    GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
  {
    foreach (IElement element in
      GetModelElementsFromDragEvent(dragEvent))
    {
      IConnectableElement part = element as IConnectableElement;
      if (part != null)
      {
        yield return part;
      }
    }
  }

  /// <summary>
  /// Retrieves UML IElements from drag arguments.
  /// Works for drags from UML diagrams.
  /// </summary>
  private IEnumerable<IElement> GetModelElementsFromDragEvent
          (DiagramDragEventArgs dragEvent)
  {
    //ElementGroupPrototype is the container for
    //dragged and copied elements and toolbox items.
    ElementGroupPrototype prototype =
       dragEvent.Data.
       GetData(typeof(ElementGroupPrototype))
            as ElementGroupPrototype;
    // Locate the originals in the implementation store.
    IElementDirectory implementationDirectory =
       dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;

    return prototype.ProtoElements.Select(
      prototypeElement =>
      {
        ModelElement element = implementationDirectory
          .FindElement(prototypeElement.ElementId);
        ShapeElement shapeElement = element as ShapeElement;
        if (shapeElement != null)
        {
          // Dragged from a diagram.
          return shapeElement.ModelElement as IElement;
        }
        else
        {
          // Dragged from UML Model Explorer.
          return element as IElement;
        }
      });
  }

  public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
  {
  }
}

Код метода GetModelElementsFromDragEvent() содержится в Практическое руководство. Получение элементов модели UML из IDataObject.

См. также

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

Практическое руководство. Определение и установка расширения моделирования

Расширение моделей и схем UML

Практическое руководство. Определение команды меню на схеме моделирования

Практическое руководство. Определение ограничений проверки для моделей UML

Программирование с UML API