HOW TO:在模型圖表上定義功能表命令
在 Visual Studio Ultimate,您可以在 UML 圖表的捷徑功能表上定義其他的功能表項目。 您可以控制在使用者以滑鼠右鍵按一下圖表上的任何項目時是否要顯示及啟用功能表命令,並且可撰寫在使用者選取功能表項目時執行的程式碼。 您可以將這些擴充功能封裝到 Visual Studio Integration Extension(VSIX) 中,並將其散發給其他Visual Studio 使用者。
需求
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 檔,並修改 CommandExtension 類別以實作您的命令。
如需詳細資訊,請參閱實作功能表命令。
您可以藉由定義新類別,將其他命令加入到這個專案。
按 F5 來測試功能表命令。 如需詳細資訊,請參閱執行功能表命令。
複製您專案建置的檔案 bin\*\*.vsix,藉此將功能表命令安裝到其他電腦上。 如需詳細資訊,請參閱安裝功能表命令。
下面為替代方法:
若要在個別的類別庫 (DLL) 專案中建立功能表命令
在一個新的或現有的 Visual Studio專案建立一個類別庫專案。
在 [檔案] 功能表上,選擇 [新增, 專案]。
在 [已安裝的範本] 下選取 [Visual C#] 或 [Visual Basic]。 在中間欄中選擇 [類別庫]。
設定 [方案],指出您想要建立新的方案,還是想要將元件加入至您已經開啟的 VSIX 方案。
設定專案名稱和位置,然後按一下 [確定]。
將下列參考加入至您的專案。
參考資料
這可讓您執行的項目
System.ComponentModel.Composition
使用 Managed Extensibility Framework (MEF) (英文) 定義元件。
Microsoft.VisualStudio.Uml.Interfaces
讀取和變更模型項目的屬性。
Microsoft.VisualStudio.ArchitectureTools.Extensibility
建立模型項目,修改圖表上的圖案。
Microsoft.VisualStudio.Modeling.Sdk.11.0
定義模型事件處理常式。
封裝模型的系列變更。 如需詳細資訊,請參閱HOW TO:使用交易連結模型更新。
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0
(不一定需要)
為筆勢處理常式存取其他圖表項目。
Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer
只有圖層圖表上的命令才需要。 如需詳細資訊,請參閱擴充圖層圖表。
定義圖層圖表上的命令。
將類別檔案加入至專案,並將類別檔案的內容設定為下列程式碼。
注意事項 依照您的偏好,變更命名空間、類別名稱以及 Text 所傳回的值。
如果您定義多個命令,它們會依照類別名稱的字母順序顯示在功能表上。
using System.ComponentModel.Composition; using System.Linq; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml; using Microsoft.VisualStudio.Modeling.ExtensionEnablement; using Microsoft.VisualStudio.Uml.AuxiliaryConstructs; using Microsoft.VisualStudio.Uml.Classes; // ADD other UML namespaces if required namespace UMLmenu1 // CHANGE { // DELETE any of these attributes if the command // should not appear in some types of diagram. [ClassDesignerExtension] [ActivityDesignerExtension] [ComponentDesignerExtension] [SequenceDesignerExtension] [UseCaseDesignerExtension] // [LayerDesignerExtension] // All menu commands must export ICommandExtension: [Export (typeof(ICommandExtension))] // CHANGE class name – determines order of appearance on menu: public class Menu1 : ICommandExtension { [Import] public IDiagramContext DiagramContext { get; set; } public void QueryStatus(IMenuCommand command) { // Set command.Visible or command.Enabled to false // to disable the menu command. command.Visible = command.Enabled = true; } public string Text { get { return "MENU COMMAND LABEL"; } } public void Execute(IMenuCommand command) { // A selection of starting points: 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 (IElement element in modelStore.AllInstances<IClass>()) { } } } }
如需應在方法中放置何種內容的詳細資訊,請參閱實作功能表命令。
您必須將功能表命令加入至 VSIX 專案,此專案可做為用於安裝命令的容器。 如果您想要,也可以在相同的 VSIX 中加入其他元件。
若要將功能表命令加入至 VSIX 專案
如果您已經建立功能表命令和它自己的 VSIX,則不需要進行此程序。
建立 VSIX 專案 (若您的方案中已有則不需建立)。
在 [方案總管]中的捷徑功能表中,選取 [新增], [新增專案]。
在 [已安裝的範本] 底下,展開 [Visual C#] 或 [Visual Basic],然後選擇 [擴充性]。 在中間的欄位中,選擇 [VSIX 專案]。
在 [方案總管] 裡的 VSIX 專案的捷徑功能表中,選取 [設定為啟始專案]。
開啟 source.extension.vsixmanifest。
在 [中繼資料] 索引標籤中將名稱設為 VSIX。
在 [安裝目標] 選項上將設定 Visual Studio Ultimate 和 Premium 做為目標。
在 [資產] 索引標籤上,選取 [新增]然後在對話方塊中設定:
類型 = MEF 元件
來源 = 在目前方案中的專案
專案 = 您的類別庫專案
實作功能表命令
功能表命令類別會實作 ICommandExtension 的必要方法。
string Text { get; } |
傳回功能表項目的標籤。 |
void QueryStatus(IMenuCommand command); |
在使用者以滑鼠右鍵按一下圖表時呼叫。 此方法不應變更模型。 使用 DiagramContext.CurrentDiagram.SelectedShapes,可以決定是否要讓命令出現,以及啟用命令。 設定:
|
void Execute (IMenuCommand command); |
如果功能表項目可見並已啟用,會在使用者按一下功能表項目時呼叫。
|
存取程式碼中的模型
請在您的功能表命令類別中加入下列宣告:
[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 (IElement element in modelStore.AllInstances<IUseCase>()) {...}
巡覽及更新模型
UML 模型的所有項目均可透過 API 來取得。 您可以從目前的選取範圍或模型的根,來存取其他所有的項目。 如需詳細資訊,請參閱HOW TO:巡覽 UML 模型與使用 UML API 進行程式設計。
如果您要處理順序圖表,請參閱HOW TO:使用 UML API 編輯順序圖表。
API 也可讓您變更項目的屬性、刪除項目和關聯性,以及建立新的項目和關聯性。
根據預設,您在 Execute 方法中所做的每項變更,都將在個別的交易中執行。 使用者將無法個別復原每項變更。 如果您要將變更分組到單一交易中,請使用 HOW TO:使用交易連結模型更新中說明的 ILinkedUndoTransaction。
使用 UI 執行緒進行更新
有時候,以背景執行緒更新模型會很有用。 例如,如果您的命令會從速度緩慢的資源載入資料,您可以在背景執行緒執行載入作業,讓使用者可以看見進行中的變更,並在必要時取消作業。
但請留意,模型存放區並不具備執行緒安全。 您應一律以使用者介面 (UI) 執行緒進行更新,並盡量讓使用者無法在背景作業進行時做出編輯。 如需範例,請參閱HOW TO:從背景執行緒更新 UML 模型。
執行功能表命令
為進行測試,請在偵錯模式中執行您的命令。
若要測試功能表命令
按下 F5或是在Debug選單上選擇 開始除錯。
Visual Studio 的實驗執行個體隨即啟動。
疑難排解:如果新 Visual Studio 未啟動:
如果您具有多個專案,請確定已設定 VSIX 專案做為方案的啟始專案。
在 [方案總管] 捷徑功能表中的[啟動或唯一專案],選取 [屬性]。 在專案屬性編輯器中,選取 [偵錯] 索引標籤。 請確定 [啟動外部程式] 欄位中的字串為 Visual Studio 的完整路徑名稱,通常如下所示:
C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
在實驗性質的 Visual Studio 中,開啟或建立模型專案,然後開啟或建立模型圖表。 使用的圖表,需屬於您的功能表命令類別的屬性所列的其中一個型別。
圖表上的任何位置開啟捷徑功能表。 您的命令應該會出現在功能表中。
疑難排解:如果命令未出現在功能表上,請確定:
功能表命令專案列為 MEF 元件,其存在於資產選項裡的source.extensions.manifest的 VSIX project。
Import 和 Export 屬性的參數有效。
QueryStatus 方法不會將 command.Enabled 或 Visible 欄位設定為 false。
您所使用的模型圖表類型 (UML 類別、順序等等) 已列為其中一個功能表命令類別屬性[ClassDesignerExtension]、[SequenceDesignerExtension]等等。
安裝和解除安裝擴充功能
您可以將 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
範例
下列範例顯示功能表命令的程式碼,其會交換類別圖表上兩個項目的名稱。 這個程式碼必須建置於 Visual Studio 擴充功能專案中,並按照先前章節所述進行安裝。
using System.Collections.Generic; // for IEnumerable
using System.ComponentModel.Composition;
// for [Import], [Export]
using System.Linq; // for IEnumerable extensions
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
// for IDiagramContext
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
// for designer extension attributes
using Microsoft.VisualStudio.Modeling.Diagrams;
// for ShapeElement
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
// for IGestureExtension, ICommandExtension, ILinkedUndoContext
using Microsoft.VisualStudio.Uml.Classes;
// for class diagrams, packages
/// <summary>
/// Extension to swap names of classes in a class diagram.
/// </summary>
namespace SwapClassNames
{
// Declare the class as an MEF component:
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension]
// Add more ExportMetadata attributes to make
// the command appear on diagrams of other types.
public class NameSwapper : ICommandExtension
{
// MEF required interfaces:
[Import]
public IDiagramContext Context { get; set; }
[Import]
public ILinkedUndoContext LinkedUndoContext { get; set; }
/// <summary>
/// Swap the names of the currently selected elements.
/// </summary>
/// <param name="command"></param>
public void Execute(IMenuCommand command)
{
// Get selected shapes that are IClassifiers -
// IClasses, IInterfaces, IEnumerators.
var selectedShapes = Context.CurrentDiagram
.GetSelectedShapes<IClassifier>();
if (selectedShapes.Count() < 2) return;
// Get model elements displayed by shapes.
IClassifier firstElement = selectedShapes.First().Element;
IClassifier lastElement = selectedShapes.Last().Element;
// Do the swap in a transaction so that user
// cannot undo one change without the other.
using (ILinkedUndoTransaction transaction =
LinkedUndoContext.BeginTransaction("Swap names"))
{
string firstName = firstElement.Name;
firstElement.Name = lastElement.Name;
lastElement.Name = firstName;
transaction.Commit();
}
}
/// <summary>
/// Called by Visual Studio to determine whether
/// menu item should be visible and enabled.
/// </summary>
public void QueryStatus(IMenuCommand command)
{
int selectedClassifiers = Context.CurrentDiagram
.GetSelectedShapes<IClassifier>().Count();
command.Visible = selectedClassifiers > 0;
command.Enabled = selectedClassifiers == 2;
}
/// <summary>
/// Name of the menu command.
/// </summary>
public string Text
{
get { return "Swap Names"; }
}
}
}