HOW TO:在模型圖表上定義筆勢處理常式
在 Visual Studio Ultimate ,您可以定義當使用者按兩下項目或將項目拖曳到 UML 圖表時執行的命令。您可以將這些擴充功能封裝成 Visual Studio Integration Extension (VSIX) 並將其散布給其他 Visual Studio Ultimate 使用者。
如果您要拖曳的圖表類型與項目型別已有內建行為,您可能無法加入更多行為或覆寫此行為。
需求
Visual Studio SDK 是一個您可以從 Visual Studio 組件庫取得的東西。
Visual Studio Visualization and Modeling SDK 是一個您可以從 Visual Studio Visualization and Modeling SDK on Code Gallery取得的東西。
建立筆勢處理常式
若要定義 UML 設計工具的筆勢處理常式,您必須建立會定義筆勢處理常式行為的類別,並將類別內嵌在 Visual Studio Integration Extension (VSIX) 中。VSIX 可做為能安裝處理常式的容器。定義筆勢處理常式的替代方法有二種:
**使用專案範本在它自己的 VSIX 中建立筆勢處理常式。**這是較快速的方法。如果您不要將您的處理常式與其他類型的擴充功能 (例如,驗證擴充功能、自訂工具箱項目或功能表命令) 結合在一起,請使用此方法。
**建立個別的處理常式和 VSIX 專案。**如果您要將數個擴充功能類型結合成相同的 VSIX,請使用此方法。例如,如果您的筆勢處理常式預期模型會遵守特定的約束條件,則可以將它內嵌在相同的 VSIX 做為驗證方法。
若要在它自己的 VSIX 中建立筆勢處理常式
在 [新增專案] 對話方塊的 [模型專案] 底下,選取 [筆勢擴充功能]。
開啟新專案中的 .cs 檔,並修改 GestureExtension 類別以實作您的筆勢處理常式。
如需詳細資訊,請參閱實作筆勢處理常式。
按 F5 來測試筆勢處理常式。如需詳細資訊,請參閱執行筆勢處理常式。
複製您專案建置的檔案 bin\*\*.vsix,藉此將筆勢處理常式安裝到其他電腦上。如需詳細資訊,請參閱安裝筆勢處理常式。
下面為替代方法:
若要建立一個手勢處理程序的分離類別庫 (DLL) 專案
在新的 Visual Studio 方案或現有的方案中建立類別庫專案。
在 [檔案] 功能表上,選擇 [新增, 專案]。
在 [已安裝的範本] 底下,擴展[Visual C#] 或 [Visual Basic],然後在中間的欄位中,選取 [類別庫]。
將下列參考加入至您的專案。
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 – 如果您要擴充圖層圖表則需要它。如需詳細資訊,請參閱擴充圖層圖表。
將類別檔案加入至專案,並將類別檔案的內容設定為下列程式碼。
注意事項 依照您的偏好變更命名空間和類別名稱。
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 專案
如果您已經建立手勢處理程序和它自己的 VSIX,則不需要進行此程序。
建立 VSIX 專案 (若您的方案中已有則不需建立)。
在 [方案總管]中的捷徑功能表中,選取 [新增], [新增專案]。
在 [已安裝的範本] 底下,展開 [Visual C#] 或 [Visual Basic],然後選取 [擴充性]。在中間的欄位中,選擇 [VSIX 專案]。
將 VSIX 專案設定為方案的啟始專案。
- 在 方案總管]裡的 VSIX 專案的捷徑功能表中,選取 [設定為啟始專案]。
在 source.extension.vsixmanifest ,加入手勢處理程序類別庫專案做為 MEF 元件。
在 [中繼資料] 索引標籤中將名稱設為 VSIX。
在 [安裝目標] 選項上將設定 Visual Studio Ultimate 和 Premium 做為目標。
在 [資產] 索引標籤上,選取 [新增]然後在對話方塊中設定:
類型 = MEF 元件
來源 = 在目前方案中的專案
專案 = 您的類別庫專案
執行筆勢處理常式
為進行測試,請在偵錯模式中執行您的筆勢處理常式。
若要測試筆勢處理常式
按下 F5,或在 [偵錯] 功能表上,按一下 [開始偵錯]。
Visual Studio 的實驗執行個體隨即啟動。
疑難排解:如果新 Visual Studio 未啟動:
如果您具有多個專案,請確定已設定 VSIX 專案做為方案的啟始專案。
在 [方案總管] 捷徑功能表中的[啟動或唯一專案],選取 [屬性]。在專案屬性編輯器中,選取 [偵錯] 索引標籤。請確定 [啟動外部程式] 欄位中的字串為 Visual Studio 的完整路徑名稱,通常如下所示:
C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
在實驗性質的 Visual Studio 中,開啟或建立模型專案,然後開啟或建立模型圖表。使用的圖表,需屬於您的筆勢處理常式類別的屬性所列的其中一個型別。
按兩下圖表上的任何位置。此時應會呼叫您的 double-click 處理常式。
將項目從 [UML 總管] 拖曳至圖表。此時應會呼叫您的拖曳處理常式。
疑難排解:如果筆勢處理常式未執行,請確定:
手勢處理程序專案已列為VSIX 專案中的 MEF 元件在 資產 索引標籤在 source.extensions.manifest 裡。
所有 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 擴充功能安裝在自己的電腦上,也可以安裝在其他電腦上。
若要安裝擴充功能
在您的電腦中,尋找由 VSIX 專案建置的 .vsix 檔案。
在 [方案總管]裡的VSIX 專案的捷徑功能表中,選取 [開啟 Windows 檔案總管中的資料夾]。
尋找 bin\*\YourProject.vsix 檔案
將 .vsix 檔案複製到要安裝擴充功能的目標電腦上。該電腦可以是您自己的電腦或其他電腦。
目標電腦必須具有在 source.extension.vsixmanifest 中指定的其中一個 Visual Studio 範本。
在目標電腦上開啟 .vsix 檔案。
[Visual Studio 擴充功能安裝程式] 隨即開啟,並安裝擴充功能。
啟動或重新啟動 Visual Studio。
若要解除安裝擴充功能
選擇 [工具] 功能表上的 [擴充管理員…]。
展開 [已安裝擴充功能]。
選取相應的擴充功能,然後選擇 [解除安裝]。
很少會發生因擴充功能故障而無法載入的情況,在這種情況下,錯誤視窗中會產生報告,但不會出現在 [擴充管理員] 中。如果發生無法載入的情況,您可以透過刪除以下路徑中的檔案,來移除擴充功能:
%LocalAppData%\Local\Microsoft\VisualStudio\11.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() 的程式碼。