HOW TO:在模型圖表上定義 Drop 和 Double-Click 處理常式

在 Visual Studio Ultimate,您可以定義當使用者按兩下項目或將項目拖曳到 UML 圖表時執行的命令。 您可以將這些擴充功能封裝到 Visual Studio Integration Extension (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],然後在中間的欄位中,按一下 [類別庫]。

    3. 設定 [方案],指出您想要建立新的方案,還是想要將元件加入至您已經開啟的 VSIX 方案。

    4. 設定專案名稱和位置,然後按一下 [確定]。

  2. 將下列參考加入至您的專案。

    Microsoft.VisualStudio.Modeling.Sdk.10.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.10.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. 開啟 source.extension.vsixmanifest

    2. 按一下 [加入內容]。

    3. 在 [選取內容類型] 中,選取 [MEF 元件]。

    4. 在 [選取來源] 按一下 [專案],然後選取您的筆勢處理常式類別庫專案的名稱。

  5. 按一下 [選取版本],然後選取您想要用來執行擴充功能的 Visual Studio 版本。

  6. 設定 VSIX 的名稱和描述性欄位。 儲存檔案。

執行筆勢處理常式

為進行測試,請在偵錯模式中執行您的筆勢處理常式。

若要測試筆勢處理常式

  1. 按下 F5,或在 [偵錯] 功能表上,按一下 [開始偵錯]。

    Visual Studio 的實驗執行個體隨即啟動。

    疑難排解:如果新 Visual Studio 未啟動:

    • 如果您具有多個專案,請確定已設定 VSIX 專案做為方案的啟始專案。

    • 在 [方案總管] 中,以滑鼠右鍵按一下 [啟動] 或僅按一下專案,然後按一下 [屬性]。 在專案屬性編輯器中,按一下 [偵錯] 索引標籤。 請確定 [啟動外部程式] 欄位中的字串為 Visual Studio 的完整路徑名稱,通常如下所示:

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

  2. 在實驗性質的 Visual Studio 中,開啟或建立模型專案,然後開啟或建立模型圖表。 使用的圖表,需屬於您的筆勢處理常式類別的屬性所列的其中一個型別。

  3. 按兩下圖表上的任何位置。 此時應會呼叫您的 double-click 處理常式。

  4. 將項目從 [UML 總管] 拖曳至圖表。 此時應會呼叫您的拖曳處理常式。

疑難排解:如果筆勢處理常式未執行,請確定:

  • 筆勢處理常式專案在 VSIX 專案之 source.extensions.manifest 的 [內容] 清單中,已列為 MEF 元件。

  • 所有 Import 和 Export 屬性的參數皆有效。

  • CanDragDrop 方法未傳回 false。

  • 您所使用的模型圖表類型 (UML 類別、順序等等) 已列為其中一個筆勢處理常式類別屬性 [ClassDesignerExtension]、[SequenceDesignerExtension] 等。

  • 此類型的目標與已置放項目沒有任何已定義的內建功能。

實作筆勢處理常式

筆勢處理常式方法

筆勢處理常式類別會實作和匯出 IGestureExtension。 您需要定義的方法如下:

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

傳回 true,以允許在此目標上置放 dragEvent 中參考的來源項目。

此方法不應變更模型。 它應該快速運作,因為其用途為在使用者移動滑鼠時判斷箭號狀態。

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

更新以 dragEvent 中參考的來源物件為基礎的模型,以及目標。

使用者在拖曳後放開滑鼠時呼叫。

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target 是使用者按兩下的圖案。

您可以撰寫處理常式,來接受 UML 和各種其他項目,例如 .NET 類別檢視的檔案、節點,以及 [架構總管] 節點等。 如果您撰寫可解碼這些項目之序列化格式的 OnDragDrop 方法,使用者就可以將任何項目拖曳至 UML 圖表上。 解碼方法根據項目型別的不同而不同。

這些方法的參數為:

  • ShapeElement target. 使用者從中拖曳某項目的圖案或圖表。

    ShapeElement 類別在實作中是 UML 模型工具的基礎。 若要降低造成 UML 模型和圖表狀態不一致的風險,建議您不要直接使用此類別的方法。 請將項目包裝在 IShape 中,然後使用 HOW TO:在圖表上顯示模型中所說明的方法。

    • 若要取得 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 項目,請參閱 HOW TO:從 IDataObject 取得 UML 模型項目

撰寫方法的程式碼

如需撰寫程式碼以讀取和更新模型的詳細資訊,請參閱使用 UML API 進行程式設計

如需透過拖曳作業存取模型資訊的詳細資訊,請參閱 HOW TO:從 IDataObject 取得 UML 模型項目

如果您要處理順序圖表,請參閱HOW TO:使用 UML API 編輯順序圖表

除了方法的參數以外,您也可以在類別中宣告可供存取目前圖表和模型的匯入屬性。

[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>) {...}

如需詳細資訊,請參閱 HOW TO:巡覽 UML 模型

安裝和解除安裝擴充功能

您可以將 Visual Studio 擴充功能安裝在自己的電腦上,也可以安裝在其他電腦上。

若要安裝擴充功能

  1. 在您的電腦中,尋找由 VSIX 專案建置的 .vsix 檔案。

    1. 在 [方案總管] 中,以滑鼠右鍵按一下 VSIX 專案,然後按一下 [在 Windows 檔案總管中開啟資料夾]。

    2. 尋找 bin\*\YourProject.vsix 檔案

  2. .vsix 檔案複製到要安裝擴充功能的目標電腦上。 該電腦可以是您自己的電腦或其他電腦。

    目標電腦必須具有在 source.extension.vsixmanifest 中指定的其中一個 Visual Studio 範本。

  3. 在目標電腦上,按兩下 .vsix 檔案。

    [Visual Studio 擴充功能安裝程式] 隨即開啟,並安裝擴充功能。

  4. 啟動或重新啟動 Visual Studio。

若要解除安裝擴充功能

  1. 按一下 [工具] 功能表上的 [擴充管理員]。

  2. 展開 [已安裝擴充功能]。

  3. 選取相應的擴充功能,然後按一下 [解除安裝]。

很少會發生因擴充功能故障而無法載入的情況,在這種情況下,錯誤視窗中會產生報告,但不會出現在 [擴充管理員] 中。 如果發生無法載入的情況,您可以透過刪除以下路徑中的檔案,來移除擴充功能:

%LocalAppData%\Local\Microsoft\VisualStudio\10.0\Extensions

範例

下列範例說明如何根據從元件圖表中拖曳之元件的組件和連接埠,在順序圖表中建立生命線。

若要加以測試,請按 F5。 Visual Studio 的實驗執行個體隨即開啟。 在此執行個體中開啟 UML 模型,並在元件圖表上建立元件。 在此元件中加入某些介面和內部元件組件。 選取介面和組件。 然後,將介面和組件拖曳至順序圖表上 (從元件圖表向上拖曳至順序圖表的索引標籤,然後向下拖曳至順序圖表中)。每個介面和組件都會出現生命線。

如需將互動繫結至順序圖表的詳細資訊,請參閱HOW TO:使用 UML API 編輯順序圖表

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

HOW TO:從 IDataObject 取得 UML 模型項目 中會說明 GetModelElementsFromDragEvent() 的程式碼。

請參閱

其他資源

HOW TO:定義與安裝模型擴充功能

擴充 UML 模型與圖表

HOW TO:在模型圖表上定義功能表命令

HOW TO:定義 UML 模型的驗證條件約束

使用 UML API 進行程式設計