HOW TO:在圖表上顯示模型
在 Visual Studio Ultimate 擴充功能的程式碼中,您可以控制模型項目在圖表上顯示的方式。
本主題內容:
若要在圖表上顯示項目
存取代表項目的圖案
移動圖案及調整圖案大小
若要從圖表移除圖案
開啟及建立圖表
範例:對齊圖案的命令
若要在圖表上顯示項目
當您建立項目 (例如,使用案例或動作) 時,使用者可以在 [UML 模型總管] 中看見該項目,但是該項目不一定會自動出現在圖表中。在某些情況下,您必須撰寫程式碼來顯示它。下表摘要說明一些替代方法。
項目的類型 |
例如 |
若要顯示此內容,您的程式碼必須 |
---|---|---|
Classifier |
Class Component Actor Use Case |
在指定的圖表上建立相關聯的圖案。您可以為每一個 Classifier 建立任意數目的圖案。 diagram.Display<modelElementType> (modelElement, parentShape, xPosition , yPosition); 針對圖表頂端的圖案,將 parentShape 設為 null。 在某一個圖案內顯示另一個圖案。 IShape<IUseCase> usecaseShape = useCaseDiagram.Display (useCase, subsystemShape, subsystemShape.XPosition + 5, subsystemShape.YPosition + 5);
注意事項
如果您在 ILinkedUndo 交易內執行 Display,這個方法有時候不會傳回 IShape,但是圖案會正確建立,並且可以使用 IElement.Shapes(). 存取。
|
Classifier 的子系 |
屬性、作業、 組件、通訊埠 |
自動:不需要程式碼。 它會做為父系的一部分顯示。 |
行為 |
互動 (序列), 活動 |
將行為繫結至適當的圖表。 每一個行為每次最多可以繫結至一個圖表。 例如: sequenceDiagram.Bind(interaction); activityDiagram.Bind(activity); |
行為的子系 |
生命線、訊息、動作、物件節點 |
自動:不需要程式碼。 它會在父系繫結至圖表時顯示。 |
關聯性 |
關聯、一般化、流程、相依性 |
自動:不需要程式碼。 它會在兩端都顯示的每一個圖表上顯示。 |
存取代表項目的圖案
代表項目的圖案屬於下列型別:
IShape
IShape<ElementType>
其中 ElementType 是模型項目的型別,例如 IClass 或 IUseCase。
anElement.Shapes () |
開啟的圖表中所有表示此項目的 IShapes。 |
anElement.Shapes(aDiagram) |
在特殊圖表上表示此項目的所有 IShapes。 |
anIShape.GetElement() |
圖案所表示的 IElement。您通常會將其轉換成 IElement 的子類別。 |
anIShape.Diagram |
包含圖案的 IDiagram。 |
anIShape.ParentShape |
包含 anIShape 的圖案。例如,通訊埠圖案包含在元件圖案內。 |
anIShape.ChildShapes |
IShape 或 IDiagram 內含的圖案。 |
anIShape.GetChildShapes<IUseCase>() |
IShape 或 IDiagram 內含的圖案,代表指定型別的項目,例如 IUseCase。 |
IShape iShape = ...; IShape<IClass> classShape = iShape.ToIShape<IClass>(); IClass aClass = classShape.Element; |
將泛型 IShape 轉換成強型別 IShape<IElement>。 |
IShape<IClassifier> classifierShape; IShape<IUseCase> usecaseShape = classifierShape.ToIShape<IUseCase>(); |
在參數化圖案型別之間轉換圖案。 |
移動圖案及調整圖案大小
anIShape.Move(x, y, [width], [height]) |
移動圖案或調整圖案大小。 |
IDiagram.EnsureVisible( IEnumerable<IShape> shapes, bool zoomToFit = false) |
啟動視窗並捲動圖表,使所有指定的圖案都能呈現。這些圖案全都必須在圖表上。如果 zoomToFit 為 true,圖表即會視需要進行縮放,使所有圖案都能呈現。 |
如需範例,請參閱定義對齊命令。
若要從圖表移除圖案
您可以刪除一些項目類型的圖案,而不刪除該項目。
模型項目 |
若要移除圖案 |
---|---|
Classifier:類別、介面、列舉、行動、使用案例或元件 |
shape.Delete(); |
行為:互動或活動 |
您可以從專案中刪除圖表。請使用 IDiagram.FileName 取得路徑。 這樣做不會刪除模型的行為。 |
任何其他圖案 |
您無法明確刪除圖表中的其他圖案。如果從模型中刪除項目,或是從圖表中移除父圖案,則圖案將自動消失。 |
開啟及建立圖表
若要從命令或軌跡擴充功能存取使用者目前的圖表
在類別中宣告此匯入的屬性:
[Import]
IDiagramContext Context { get; set; }
在方法中存取圖表:
IClassDiagram classDiagram =
Context.CurrentDiagram as IClassDiagram;
注意事項 |
---|
只有在您所處理的命令中,IDiagram 的執行個體 (及其子類型,如 IClassDiagram) 才有效。建議您不要將 IDiagram 物件保存在使用者重新取得控制權後仍會保留的變數中。 |
如需詳細資訊,請參閱HOW TO:在模型圖表上定義功能表命令。
若要取得開啟圖表的清單
專案中目前開啟之圖表的清單:
Context.CurrentDiagram.ModelStore.Diagrams()
若要存取專案中的圖表
Visual Studio API 可用以開啟及建立模型專案和圖表。
請留意從 EnvDTE.ProjectItem 到 IDiagramContext 的轉換。
using EnvDTE; // Visual Studio API
...
[Import]
public IServiceProvider ServiceProvider { get; set; }
...
// Get Visual Studio API
DTE dte = ServiceProvider.GetService(typeof(DTE)) as DTE;
// Get current Visual Studio project
Project project = dte.ActiveDocument.ProjectItem.ContainingProject;
// Open and process every diagram in the project.
foreach (ProjectItem item in project.ProjectItems)
{
// Cast ProjectItem to IDiagramContext
IDiagramContext context = item as IDiagramContext;
if (context == null)
{
// This is not a diagram file.
continue;
}
// Open the file and give the window the focus.
if (!item.IsOpen)
{
item.Open().Activate();
}
// Get the diagram.
IDiagram diagram = context.CurrentDiagram;
// Deal with specific diagram types.
ISequenceDiagram seqDiagram = diagram as ISequenceDiagram;
if (seqDiagram != null)
{ ... } } }
在您將控制權傳回給 Visual Studio 後,IDiagram 的執行個體及其子類型即無效。
您也可以從 Visual Studio 專案取得模型存放區:
Project project = ...;
IModelStore modelStore = (project as IModelingProject).Store;
範例:對齊圖案的命令
下列程式碼實作工整對齊圖案的功能表命令。使用者必須先以接近垂直或水平對齊的方式放置兩個以上的圖案。接著對齊命令可用來將圖案置中對齊。
若要讓使用者使用此命令,請將此程式碼加入至功能表命令專案,然後部署產生的擴充功能。如需詳細資訊,請參閱HOW TO:在模型圖表上定義功能表命令。
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace AlignCommand
{
// Implements a command to align shapes in a UML class diagram.
// The user first selects shapes that are roughly aligned either vertically or horizontally.
// This command will straighten them up.
// Place this file in a menu command extension project.
// See https://msdn.microsoft.com/library/ee329481.aspx
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension] // TODO: Add other diagram types if needed
class CommandExtension : ICommandExtension
{
/// <summary>
/// See https://msdn.microsoft.com/library/ee329481.aspx
/// </summary>
[Import]
IDiagramContext context { get; set; }
/// <summary>
/// Transaction context.
/// See https://msdn.microsoft.com/library/ee330926.aspx
/// </summary>
[Import]
ILinkedUndoContext linkedUndo { get; set; }
/// <summary>
/// Called when the user selects the command.
/// </summary>
/// <param name="command"></param>
public void Execute(IMenuCommand command)
{
Align(context.CurrentDiagram.SelectedShapes);
}
/// <summary>
/// Called when the user right-clicks on the diagram.
/// Determines whether the command is enabled.
/// </summary>
/// <param name="command"></param>
public void QueryStatus(IMenuCommand command)
{
IEnumerable<IShape> currentSelection = context.CurrentDiagram.SelectedShapes;
// Make it visible if there are shapes selected:
command.Visible = currentSelection.Count() > 0 && !(currentSelection.FirstOrDefault() is IDiagram);
// Make it enabled if there are two or more shapes that are roughly in line:
command.Enabled = currentSelection.Count() > 1
&& (HorizontalAlignCenter(currentSelection) > 0.0
|| VerticalAlignCenter(currentSelection) > 0.0);
}
/// <summary>
/// Title of the menu command.
/// </summary>
public string Text
{
get { return "Align Shapes"; }
}
/// <summary>
/// Find a horizontal line that goes through a list of shapes.
/// </summary>
/// <param name="shapes"></param>
/// <returns></returns>
private static double HorizontalAlignCenter(IEnumerable<IShape> shapes)
{
double Y = -1.0;
double top = 0.0, bottom = shapes.First().Bottom();
foreach (IShape shape in shapes)
{
top = Math.Max(top, shape.Top());
bottom = Math.Min(bottom, shape.Bottom());
}
if (bottom > top) Y = (bottom + top) / 2.0;
return Y;
}
/// <summary>
/// Find a vertical line that goes through a list of shapes.
/// </summary>
/// <param name="shapes"></param>
/// <returns></returns>
private static double VerticalAlignCenter(IEnumerable<IShape> shapes)
{
double X = -1.0;
double left = 0.0, right = shapes.First().Right();
foreach (IShape shape in shapes)
{
left = Math.Max(left, shape.Left());
right = Math.Min(right, shape.Right());
}
if (right > left) X = (right + left) / 2.0;
return X;
}
/// <summary>
/// Line up those shapes that are roughly aligned.
/// </summary>
/// <param name="shapes"></param>
private void Align(IEnumerable<IShape> shapes)
{
if (shapes.Count() > 1)
{
// The shapes must all overlap either horizontally or vertically.
// Find a horizontal line that is covered by all the shapes:
double Y = HorizontalAlignCenter(shapes);
if (Y > 0.0) // Negative if they don't overlap.
{
// Adjust all the shape positions in one transaction:
using (ILinkedUndoTransaction t = linkedUndo.BeginTransaction("align"))
{
foreach (IShape shape in shapes)
{
shape.AlignYCenter(Y);
}
t.Commit();
}
}
else
{
// Find a vertical line that is covered by all the shapes:
double X = VerticalAlignCenter(shapes);
if (X > 0.0) // Negative if they don't overlap.
{
// Adjust all the shape positions in one transaction:
using (ILinkedUndoTransaction t = linkedUndo.BeginTransaction("align"))
{
foreach (IShape shape in shapes)
{
shape.AlignXCenter(X);
}
t.Commit();
}
}
}
}
}
}
/// <summary>
/// Convenience extensions for IShape.
/// </summary>
public static class IShapeExtension
{
public static double Bottom(this IShape shape)
{
return shape.YPosition + shape.Height;
}
public static double Top(this IShape shape)
{
return shape.YPosition;
}
public static double Left(this IShape shape)
{
return shape.XPosition;
}
public static double Right(this IShape shape)
{
return shape.XPosition + shape.Width;
}
public static void AlignYCenter(this IShape shape, double Y)
{
shape.Move(shape.XPosition, Y - shape.YCenter());
}
public static void AlignXCenter(this IShape shape, double X)
{
shape.Move(X - shape.XCenter(), shape.YPosition);
}
/// <summary>
/// We can adjust what bit of the shape we want to be aligned.
/// The default is the center of the shape.
/// </summary>
/// <param name="shape"></param>
/// <returns></returns>
public static double YCenter(this IShape shape)
{
return shape.Height / 2.0;
}
/// <summary>
/// We can adjust what bit of the shape we want to be aligned.
/// The default is the center of the shape.
/// </summary>
/// <param name="shape"></param>
/// <returns></returns>
public static double XCenter(this IShape shape)
{
return shape.Width / 2.0;
}
}
}