在程序代码中导航和更新模型

可以创建和删除模型元素中编写代码,设置其属性,并创建和删除元素之间的链接。必须在事务内进行更改。如果元素在关系图中查看,关系图 “将自动已修复”在事务末尾。

主题内容

DSL 定义示例

导航模型

访问信息的类。

执行事务内的更改

创建模型元素

创建链接关系

删除元素

删除关系链接

重新排序的链接关系

锁定

复制和粘贴

导航和更新关系图

在形状和元素之间

形状和连接线属性

DocView 和 DocData

形状、连接和关系图及其关系到模型元素在单独的主题中进行说明。有关更多信息,请参见 [重定向] 如何:导航和更新图表

DSL 定义示例

这是 DslDefinition.dsl 的主要部分示例的此主题:

DSL 定义关系图 - 家谱模型

此模型是此 DSL 实例:

都铎王朝家谱模型

Cc512845.collapse_all(zh-cn,VS.110).gif引用和命名空间

若要运行本主题中的代码,则应引用:

Microsoft.VisualStudio.Modeling.Sdk.11.0.dll

代码将使用此命名空间:

using Microsoft.VisualStudio.Modeling;

此外,因此,如果在从 DSL 定义的线程以外的其他项目中编写代码,则应导入由 DSL 项目生成的程序集。

导航模型

Cc512845.collapse_all(zh-cn,VS.110).gif属性

在 DSL 定义的字段属性将成为您可以在程序代码中访问属性:

Person henry = ...;

if (henry.BirthDate < 1500) ...

if (henry.Name.EndsWith("VIII")) ...

如果要设置属性,则必须先在 事务中:

henry.Name = "Henry VIII";

如果在 DSL 定义,属性的 kind计算,不能将其设置为。有关更多信息,请参见 计算的和自定义的存储属性

Cc512845.collapse_all(zh-cn,VS.110).gif关系

在 DSL 定义的字段关系成为对属性,一个在类在关系的每一端。属性的名称将显示 DslDefinition 关系图作为角色中的标签在关系的每一端。根据该角色的重数,属性的类型是类在关系的另一端或该类的集合。

foreach (Person child in henry.Children) { ... }

FamilyTreeModel ftree = henry.FamilyTreeModel;

属性在关系的相对端始终是相互的。当 LINK 创建或删除时,这两个元素的角色属性更新。使用 System.Linq扩展) 的以下表达式 (始终适用于该示例中的 ParentsHaveChildren 关系:

(Person p) => p.Children.All(child => child.Parents.Contains(p))

&& p.Parents.All(parent => parent.Children.Contains(p));

ElementLinks。关系由调用 链接的模型元素还表示,为域关系类型的实例。链接始终有一个源元素和一个目标元素。源元素和目标元素既可以是相同的。

可以访问链接及其属性:

ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);

// This is now true:

link == null || link.Parent == henry && link.Child == edward

默认情况下,不超过关系的一个实例允许链接任何对模型元素。,但是,如果在 DSL 定义, Allow Duplicates 标志适用于该关系,然后可能有一个链接,因此,您必须使用 GetLinks:

foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }

还具有访问的链接其他方法。例如:

foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }

**隐藏的角色。**如果在 DSL 定义, 是生成的属性 是某个特定角色的 错误 ,则对应于该角色的属性未生成。但是,使用该关系的方法,您仍然可以访问链接和遍历链接:

foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }

这个常用的示例是 PresentationViewsSubject 关系,具有形状模型元素链接到它显示在关系图:

PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape

Cc512845.collapse_all(zh-cn,VS.110).gif元素内容

使用元素内容,可以访问所有元素都存储:

store.ElementDirectory.AllElements

还有查找的元素的方法,例如:

store.ElementDirectory.FindElements(Person.DomainClassId);

store.ElementDirectory.GetElement(elementId);

访问信息的类。

您可以将有关类、关系和 DSL 定义的其他方面的信息。例如:

DomainClassInfo personClass = henry.GetDomainClass();

DomainPropertyInfo birthProperty =

personClass.FindDomainProperty("BirthDate")

DomainRelationshipInfo relationship =

link.GetDomainRelationship();

DomainRoleInfo sourceRole = relationship.DomainRole[0];

模型元素上级类如下所示:

  • ModelElement - 所有元素和关系是 ModelElements

  • ElementLink - 所有关系是 ElementLinks

执行事务内的更改

每当程序代码在存储更改任何内容,则必须先在事务内。这适用于任何模型元素、关系、形状、关系图及其特性。有关更多信息,请参见 Transaction

管理事务最方便的方法与 try...catch 语句中的 using 语句:

Store store; ...
try
{
  using (Transaction transaction =
    store.TransactionManager.BeginTransaction("update model"))
    // Outermost transaction must always have a name.
  {
    // Make several changes in Store:
    Person p = new Person(store);
    p.FamilyTreeModel = familyTree;
    p.Name = "Edward VI";
    // end of changes to Store

    transaction.Commit(); // Don't forget this!
  } // transaction disposed here
}
catch (Exception ex)
{
  // If an exception occurs, the Store will be 
  // rolled back to its previous state.
}

您可以在一个事务内的任意数量的更改。可以在一个活动事务内的新事务。

,在它之前,使更改永久,应 Commit 事务。如果没有捕获在事务内发生异常,存储将重置为其更改前的状态。

创建模型元素

此示例将元素添加到现有模型:

FamilyTreeModel familyTree = ...; // The root of the model.       
using (Transaction t =
    familyTree.Store.TransactionManager
    .BeginTransaction("update model"))
{
  // Create a new model element 
  // in the same partition as the model root:
  Person edward = new Person(familyTree.Partition);
  // Set its embedding relationship:
  edward.FamilyTreeModel = familyTree;
          // same as: familyTree.People.Add(edward);
  // Set its properties:
  edward.Name = "Edward VII";
  t.Commit(); // Don't forget this!
}

此示例演示以下基本指向有关创建元素:

  • 创建新组件中存储的特定分区。对于模型元素和不显示关系,但是,形状,这通常是默认分区。

  • 使其成为个目标一个嵌入的关系。在本示例的 DslDefinition,每个人都必须是嵌入关系的目标 FamilyTreeHasPeople。为此,我们可以设置 person 对象的 FamilyTreeModel 角色特性,或者添加用户。 FamilyTreeModel 对象的用户角色的属性。

  • 设置新的元素的属性,特定属性 IsName 为 true。 DslDefinition。此标志指示服务在其所有者中唯一标识元素的属性。在这种情况下,属性名称具有该标志。

  • 必须加载了此 DSL 的 DSL 定义到存储。如果要编写扩展 (如菜单命令,这通常是已经为 true。在某些情况下,您可以显式加载该模型来存储,或使用 ModelBus 加载它。有关更多信息,请参见 如果:在程序代码中从文件打开模型

在此类中创建一个元素,则形状自动创建 (如果 DSL 具有关系图)。带有自动指派的位置显示,具有默认形状、颜色和其他功能。如果要控制关联的形状的位置和如何显示,请参见 创建组件及其形状。

创建链接关系

在示例 DSL 定义的两个关系。每个关系定义了类的一个 角色 关系中的每一端。

可以创建关系的实例的三种方式。这三个方法中的每一个都具有相同的效果:

  • 设置源角色扮演者的属性。例如:

    • familyTree.People.Add(edward);

    • edward.Parents.Add(henry);

  • 设置目标角色扮演者的属性。例如:

    • edward.familyTreeModel = familyTree;

      此角色重数都为 1..1,因此,我们将值。

    • henry.Children.Add(edward);

      此角色重数都为 0..*,因此,我们添加到集合中。

  • 显式构造一个实例该关系。例如:

    • FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);

    • ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);

,如果要对该关系的属性,最后一个方法很有用。

在此类中创建一个元素,该关系图的连接自动创建,但是,它具有默认形状,颜色和其他功能。若要控制关联的连接如何创建,请参见 创建组件及其形状。

删除元素

通过调用 Delete()删除元素:

henry.Delete();

此操作还将删除:

  • 来回元素的关系链接。例如, edward.Parents 将不再包含 henry。

  • 在 PropagatesDelete 标志真实的角色的元素。例如,显示该元素的形状将被删除。

默认情况下,每个嵌入的关系具有 PropagatesDelete true 在目标角色。删除 henry 不删除 familyTree,但是, familyTree.Delete() 将删除所有 Persons。有关更多信息,请参见 自定义删除行为

默认情况下, PropagatesDelete 不适用于角色引用关系。

,则删除对象时,可以生成删除规则省略特定发送。,如果您在调用代码中,用一个元素时很有用。为删除不应传播一个或多个角色的 GUID。GUID 可以从关系类获取:

henry.Delete(ParentsHaveChildren.SourceDomainRoleId);

(此特定示例将不起作用,因为, PropagatesDelete 是 ParentsHaveChildren 关系的角色的 false 。)

有时,删除由固定存在防止,在元素或在将由发送移除的元素。可以使用 element.CanDelete() 检查该元素是否能删除。

删除关系链接

可以通过移除元素删除关系链接到角色特性:

henry.Children.Remove(edward); // or:

edward.Parents.Remove(henry); // or:

可以显式中删除该链接:

edwardHenryLink.Delete();

这三个方法都具有相同的效果。只需使用其中之一。

如果该角色具有或 1..1 重数 0..1,可以将其设置为 null,或者为其他值:

edward.FamilyTreeModel = null; //或:

edward.FamilyTreeModel = anotherFamilyTree;

重新排序的链接关系

是源或目标在特定模型元素特定关系的链接都有特定顺序。按其添加的顺序显示。例如,此语句将始终为子项的顺序:

foreach (Person child in henry.Children) ...

可以更改链接的顺序:

ParentsHaveChildren link = GetLink(henry,edward);

ParentsHaveChildren nextLink = GetLink(henry, elizabeth);

DomainRoleInfo role =

link.GetDomainRelationship().DomainRoles[0];

link.MoveBefore(role, nextLink);

锁定

更改可能受到锁定被禁止。锁可能设置在单独的组件,在分区和在存储。如果这些级别中的任何一个具有防止这将要进行的锁,异常可能会引发,如果尝试它。可以查看锁定通过使用元素,是否设置为。GetLocks(),是扩展方法。 Immutability定义。

有关更多信息,请参见 定义锁定策略以创建只读段

复制和粘贴

可以复制元素的元素或组添加到 IDataObject:

Person person = personShape.ModelElement as Person;
Person adopter = adopterShape.ModelElement as Person;
IDataObject data = new DataObject();
personShape.Diagram.ElementOperations
      .Copy(data, person.Children.ToList<ModelElement>());

元素存储为已序列化的元素组。

可以将 IDataObject 的元素添加到模型:

using (Transaction t = targetDiagram.Store.
        TransactionManager.BeginTransaction("paste"))
{
  adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}

Merge () 可以接受 PresentationElement 或 ModelElement。如果您赋予它 PresentationElement,还可以指定在目标关系图中的位置作为第三个参数。

导航和更新关系图

在 DSL,域模型元素,表示一个概念 (如人员或歌曲,与形状元素,表示想要在关系图参见。域模型元素存储概念的重要属性和关系。形状元素在关系图上存储大小、对象的视图的位置和颜色及其构成格式。

Cc512845.collapse_all(zh-cn,VS.110).gif显示元素

基本形状和元素类型的类图

在 DSL 定义,指定的每个元素创建从以下条件类之一派生的类。

元素类型

基类

域类

ModelElement

域关系

ElementLink

形状

NodeShape

连接

BinaryLinkShape

关系图

Diagram

关系图上的元素通常表示一个模型元素。通常 (,但不总是), NodeShape 表示字段类的实例,并且, BinaryLinkShape 表示域关系实例。PresentationViewsSubject 关系与它表示的模型元素链接节点或链接形状。

每个节点或链接形状属于一个关系图。二进制链接形状连接两个节点形状。

形状可以在两个形状设置的子级。在设置的 NestedChildShapes 的形状限于边界框其父级。在 RelativeChildShapes 的例如形状列表可以在父级之外外部或部分显示 –标签或端口的区域。关系图没有 RelativeChildShapes 和 Parent。

Cc512845.collapse_all(zh-cn,VS.110).gif在形状和元素之间

域模型元素和形状元素由 PresentationViewsSubject 关系关联。

// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape = 
  PresentationViewsSubject.GetPresentation(henry)
    .FirstOrDefault() as PersonShape;

同一关系链接到连接的关系在关系图:

Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
   PresentationViewsSubject.GetPresentation(link)
     .FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape

此关系与关系图来链接到模型的根:

FamilyTreeDiagram diagram = 
   PresentationViewsSubject.GetPresentation(familyTree)
      .FirstOrDefault() as FamilyTreeDiagram;

获取形状表示的模型元素,请使用:

henryShape.ModelElement as Person

diagram.ModelElement as FamilyTreeModel

Cc512845.collapse_all(zh-cn,VS.110).gif在关系图的任何

通常在形状和连接线之间在关系图中不可行。,仅当在关系图的外观时,工作所必需的定位在设计的关系,用于将形状和连接线之间最好。这些方法具有形状链接连接在每个末尾:

personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes

connector.FromShape, connector.ToShape

许多形状是复合;它们由父形状和子组成一个或多个层。将相对于其他形状的形状被视为其 子项。当父形状移动时, child 随之移动。

相对子级 可以显示外部父形状的边界框。嵌套 子强显示在父的边界内。

若要获取顶部设置关系图中的形状,请使用:

Diagram.NestedChildShapes

形状和连接线上级的类包括:

ModelElement

-- PresentationElement

-- ShapeElement

----- NodeShape

------- Diagram

------- TheShape

----- LinkShape

------- BinaryLinkShape

--------- TheConnector

Cc512845.collapse_all(zh-cn,VS.110).gif形状和连接线属性

在大多数情况下,对形状的显式更改并不是必需的。当您更改了模型元素时, “修复”规则更新形状和连接线。有关更多信息,请参见 响应并传播更改

但是,对形状的这些显式更改在模型元素无关的属性是很有用的。例如,您可以更改以下属性:

  • Size - 定位形状的高度和宽度。

  • Location - 相对于父形状或关系图的位置

  • StyleSet - 设置钢笔和画笔进行绘制形状或使用了连接

  • Hide - 使形状可见

  • Show - 使形状显示在 Hide()之后

Cc512845.collapse_all(zh-cn,VS.110).gif创建组件及其形状

当您创建元素并将其链接到嵌入关系时树,则形状自动创建并与它。这是通过对事务末尾的 “fixup”规则完成。但是,形状于一自动分配的位置将出现,并且,其形状、颜色和其他功能将具有默认值。若要控制形状如何创建,可以使用组合函数。您必须先添加要添加到 ElementGroup 的组件,然后将组添加到关系图。

此方法:

  • ,如果分配了属性作为元素名称,将名称。

  • 观察在 DSL 定义指定的所有元素合并指令。

,当用户双击关系图时,此示例创建形状在光标位置。本示例的 DSL 定义, ExampleShapeFillColor 属性显示。

  using Microsoft.VisualStudio.Modeling;
  using Microsoft.VisualStudio.Modeling.Diagrams;
  partial class MyDiagram
  {
    public override void OnDoubleClick(DiagramPointEventArgs e)
    {
      base.OnDoubleClick(e);

      using (Transaction t = this.Store.TransactionManager
          .BeginTransaction("double click"))
      {
        ExampleElement element = new ExampleElement(this.Store);
        ElementGroup group = new ElementGroup(element);
         
        { // To use a shape of a default size and color, omit this block.
          ExampleShape shape = new ExampleShape(this.Partition);
          shape.ModelElement = element;
          shape.AbsoluteBounds = new RectangleD(0, 0, 1.5, 1.0);
          shape.FillColor = System.Drawing.Color.Azure;
          group.Add(shape);
        }

        this.ElementOperations.MergeElementGroupPrototype(
          this,
          group.CreatePrototype(),
          PointD.ToPointF(e.MousePosition));
        t.Commit();
      }
    }
  }

如果您提供多个形状,使用 AbsoluteBounds,设置它们的相对位置。

使用此方法,还可以设置颜色和其他连接线显示的属性。

Cc512845.collapse_all(zh-cn,VS.110).gif使用事务

形状、连接和关系图是 ModelElement 子类型并存储在中。因此必须对仅其更改在事务内。有关更多信息,请参见 如何:使用事务更新模型

文档视图和文档数据

标准关系图类型的类图

存储分区

当设计加载时,附带的关系图同时加载。通常,模型加载到 Store.DefaultPartition,并且,关系图内容加载到另一个分区。通常,每个分区目录加载和保存到一个单独的文件中。

请参见

参考

ModelElement

概念

域特定语言中的验证

如何:使用事务更新模型

使用 Visual Studio Modelbus 集成模型

其他资源

从域特定语言生成代码

响应并传播更改