HOW TO:在模型圖表上定義功能表命令
在 Visual Studio Ultimate 中,您可以定義在使用者以滑鼠右鍵按一下 UML 圖表時將出現的其他功能表項目。 您可以控制在使用者以滑鼠右鍵按一下圖表上的任何項目時是否要顯示及啟用功能表命令,並且可撰寫會在使用者選取功能表項目時執行的程式碼。 您可以將這些擴充功能封裝到 Visual Studio Integration Extension (VSIX) 中,並將其散發給其他 Visual Studio Ultimate 使用者。
需求
Visual Studio 2010 視覺化和模型 SDK (英文)。 如需詳細資訊,請參閱 Code Gallery 上的 Visual Studio 視覺化和模型 SDK (英文)。
定義功能表命令
若要建立 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.10.0
定義模型事件處理常式。
封裝模型的系列變更。 如需詳細資訊,請參閱 HOW TO:使用交易連結模型更新。
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.10.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] // if you have installed Feature Pack 1 // All menu commands must export ICommandExtension: [Export (typeof(ICommandExtension))] // CHANGE class name 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 專案設定為方案的啟始專案。
在 [方案總管] 中,以滑鼠右鍵按一下 VSIX 專案,然後按一下 [設定為啟始專案]。
在 source.extension.vsixmanifest 的 [內容] 底下,加入類別庫專案當做 MEF 元件。
開啟 source.extension.vsixmanifest
按一下 [加入內容]。
在 [選取內容類型] 中,選取 [MEF 元件]。
在 [選取來源] 中,按一下 [專案],然後選取類別庫專案的名稱。
按一下 [選取版本],然後選取您想要用來執行擴充功能的 Visual Studio 版本。
設定 VSIX 的名稱和描述性欄位。 儲存檔案。
實作功能表命令
功能表命令類別會實作 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,或在 [偵錯] 功能表上,按一下 [開始偵錯]。
Visual Studio 的實驗執行個體隨即啟動。
疑難排解:如果新 Visual Studio 未啟動:
如果您具有多個專案,請確定已設定 VSIX 專案做為方案的啟始專案。
在 [方案總管] 中,以滑鼠右鍵按一下 [啟動] 或僅按一下專案,然後按一下 [屬性]。 在專案屬性編輯器中,按一下 [偵錯] 索引標籤。 請確定 [啟動外部程式] 欄位中的字串為 Visual Studio 的完整路徑名稱,通常如下所示:
C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe
在實驗性質的 Visual Studio 中,開啟或建立模型專案,然後開啟或建立模型圖表。 使用的圖表,需屬於您的功能表命令類別的屬性所列的其中一個型別。
以滑鼠右鍵按一下圖表上的任何位置。 您的命令應該會出現在功能表中。
疑難排解:如果命令未出現在功能表上,請確定:
功能表命令專案在 VSIX 專案之 source.extensions.manifest 的 [內容] 清單中,已列為 MEF 元件。
Import 和 Export 屬性的參數有效。
QueryStatus 方法不會將 command.Enabled 或 Visible 欄位設定為 false。
您所使用的模型圖表類型 (UML 類別、順序等等) 已列為其中一個功能表命令類別屬性[ClassDesignerExtension]、[SequenceDesignerExtension]等等。
安裝和解除安裝擴充功能
您可以將 Visual Studio 擴充功能安裝在自己的電腦上,也可以安裝在其他電腦上。
若要安裝擴充功能
在您的電腦中,尋找由 VSIX 專案建置的 .vsix 檔案。
在 [方案總管] 中,以滑鼠右鍵按一下 VSIX 專案,然後按一下 [在 Windows 檔案總管中開啟資料夾]。
尋找 bin\*\<您的專案>.vsix 檔案
將 .vsix 檔案複製到要安裝擴充功能的目標電腦上。 該電腦可以是您自己的電腦或其他電腦。
目標電腦必須具有在 source.extension.vsixmanifest 中指定的其中一個 Visual Studio 範本。
在目標電腦上,按兩下 .vsix 檔案。
[Visual Studio 擴充功能安裝程式] 隨即開啟,並安裝擴充功能。
啟動或重新啟動 Visual Studio。
若要解除安裝擴充功能
按一下 [工具] 功能表上的 [擴充管理員]。
展開 [已安裝擴充功能]。
選取相應的擴充功能,然後按一下 [解除安裝]。
很少會發生因擴充功能故障而無法載入的情況,在這種情況下,錯誤視窗中會產生報告,但不會出現在 [擴充管理員] 中。 如果發生無法載入的情況,您可以透過刪除以下路徑中的檔案,來移除擴充功能:
%LocalAppData%\Local\Microsoft\VisualStudio\10.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"; }
}
}
}