使用 Visual Studio Modelbus 集成模型

Visual Studio ModelBus 用于创建链接提供方法模型之间和其他工具到模型。例如,您可以链接域特定语言 (DSL)模型和 UML 模型。可以创建一组集成 DSL。

ModelBus 可以创建单个对设计或对在模型中的特定元素。该引用可以在模型外存储,例如,在元素在另一个模型。当,较高情况下,工具若要获取对元素的访问,模型总线基础结构将加载相应的设计并返回元素。如果需要,可以显示该模型给用户。如果文件不能在其以前的位置访问 ModelBus,将要求用户查找它。如果用户查找文件, ModelBus 将修复任何对该文件。

说明说明

在 ModelBus 的当前 Visual Studio 实现,链接的模型都必须位于同一个 Visual Studio 解决方案中的项目。

有关更多信息和代码示例,请参见:

提供对 DSL

在可以创建之前 ModelBus 对设计或其组件,必须定义 DSL 的 ModelBusAdapter。最简单的方法是使用 Visual Studio 模型总线扩展,将命令添加到 DSL 设计器。

显示 DSL 定义在模型总线

  1. ,除非您已安装之后,请下载并安装 Visual Studio 模型总线扩展。有关更多信息,请参见 Visualization and Modeling SDK

  2. 打开 DSL 定义文件。右击该设计图面然后单击 启用 Modelbus

  3. 在对话框中,选择 我希望显示此 DSL 在 ModelBus。可以选择两个选项,如果希望此 DSL 显示其设计,并使用对其他 DSL。

  4. 单击**“确定”**。一个新项 “ModelBusAdapter”添加到 DSL 解决方案。

  5. 如果要从文本模板访问 DSL,必须修改在新项目中 AdapterManager.tt。,如果要访问从其他代码的 DSL 例如命令和事件处理程序,则忽略此步骤。有关更多信息,请参见 在文本模板中使用 Visual Studio ModelBus

    1. 更改 AdapterManagerBase 基类。 VsTextTemplatingModelingAdapterManager

    2. 在文件末尾附近的,在类 AdapterManager 前面的此元素的其他特性:

      [Microsoft.VisualStudio.Modeling.Integration.HostSpecific(HostName)]

    3. 在引用 ModelBusAdapter 项目,添加 Microsoft.VisualStudio.TextTemplating.Modeling.11.0

    如果要访问 DSL 从文本模板和其他代码,需要两个适配器,经过修改的和非限定。

  6. 单击 转换所有模板

  7. 重新生成解决方案。

打开此 DSL 实例 ModelBus 现在是可能的。

该文件夹 ModelBusAdapters\bin\* 包含 Dsl 项目和 ModelBusAdapters 项目生成的程序集。若要引用另一个 DSL 的此 DSL,则应导入这些程序集。

Ff519531.collapse_all(zh-cn,VS.110).gif确保元素中引用

Visual Studio ModelBus 适配器使用组件的 GUID 标识, redist.txt 默认情况下。在模型文件必须保持因此这些标识符。

确保元素 ID 保持

  1. 打开 DslDefinition.dsl。

  2. 在 DSL 资源管理器中,展开 XML 序列化行为,然后 类数据

  3. 对于要创建的每个类模型总线引用:

    单击类节点,然后在 " 属性 " 窗口中,确保, 序列化 ID 设置为 true。

,或者,如果要使用元素名称标识元素而不是 GUID,可以重写生成适配器的部件。重写在适配器类的以下方法:

  • 重写返回要使用的标识符的 GetElementId 。,在创建引用时,调用此方法。

  • 重写设置从一辆模型总线了正确的组件的 ResolveElementReference 引用。

访问 DSL 从另一个 DSL

在 DSL 的字段属性可以存储模型总线引用,因此,您可以使用它们编写自定义代码。还可以让用户创建一辆模型总线通过选择一模型文件和组件引用在其中。

若要使 DSL 使用对另一个 DSL,应先进行模型总线 使用者 的引用它。

若要使 DSL 使用对一个用于 DSL

  1. 在 DSL 定义关系图,请右击关系图的主要部分然后单击 启用 Modelbus

  2. 在对话框中,选择 我想使此模型使用模型总线引用

  3. 在使用的 DSL 的 DSL 项目中,添加以下程序集到项目引用。将查找这些程序集 (.dll 文件)。 ModelBusAdapter \bin\* directory of the exposed DSL。

    • 显示的 DSL 程序集,例如 Fabrikam.FamilyTree.Dsl.dll

    • 显示的模型总线适配器程序集,例如 Fabrikam.FamilyTree.ModelBusAdapter.dll

  4. 将下面的 .NET 程序集添加到该项目引用使用的 DSL 项目。

    1. Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0.dll

    2. Microsoft.VisualStudio.Modeling.Sdk.Integration.Shell.11.0.dll

若要存储一辆模型总线引用在字段的特性

  1. 在使用的 DSL 的 DSL 定义,添加一个字段特性添加到域类并设置其名称。

  2. 在 " 属性 " 窗口中,在字段选择属性时,将 类型 到 ModelBusReference。

在此阶段,过程代码可以设置属性值,但是,它是只读在 " 属性 " 窗口中。

可以允许用户设置具有专用 ModelBus 引用的属性编辑器。具有此编辑或 选择器的 两个版本 : 一个允许用户选定一模型文件,同时,其他允许用户选定一模型文件和组件在模型中。

若要允许用户设置一辆模型总线引用在字段的特性

  1. 右击字段的特性然后单击 编辑 ModelBusReference 特定属性。对话框打开。这是 模型总线选择器。

  2. 选择适当的 类型 ModelBusReference:对一个模型或对在模型中的元素。

  3. 在文件对话框筛选器字符串,输入一个字符串 (如 Family Tree files |*.ftree。Subsitute 显示的 DSL 的文件扩展名。

  4. 如果选择在设计的一个元素,可将用户可以选择类型的列表,例如 Company.FamilyTree.Person。

  5. 单击 ,再单击 " 解决方案资源管理器工具栏的 转换所有模板

    警告说明警告

    如果未选择一个有效的设计或实体, " 确定 " 按钮将不起作用,因此,即使它可能会启用。

  6. 如果指定了目标类型列表例如 Company.FamilyTree.Person,则必须将程序集添加对 DSL 项目,引用目标 DSL 的 DLL,例如 Company.FamilyTree.Dsl.dll

若要测试一辆模型总线引用

  1. 生成显示和使用的 DSL。

  2. 一个 DSL 以实验模式通过按 F5 或 CTRL+F5 运行。

  3. 在 Visual Studio的实验实例中调试项目中,添加为每个 DSL 实例的文件。

    说明说明

    Visual Studio ModelBus 只能解析对位于同一个 Visual Studio 解决方案的项目的模型。例如,不能创建对的模型文件在文件系统的其他部分。

  4. 创建一些元素和链接中显示的 DSL 的实例,并将其保存。

  5. 打开使用的 DSL 的实例,然后选择具有此模型总线引用属性的一个模型元素。

  6. 在 " 属性 " 窗口中,双击模型总线引用属性。选择器对话框打开。

  7. 单击 浏览 并选择显示的 DSL 的实例。

    ,如果指定了元素的特定模型总线引用,选择器还将让您选择设计的项目。

创建在过程代码中引用

如果要存储对设计或在模型中的某个元素,您创建 ModelBusReference。有两 ModelBusReference:方式引用,并且元素引用。

若要创建设计引用,则需要该模型是实例 DSL 与设计的文件名或 Visual Studio 项目项的 AdapterManager。

若要创建元素引用,则需要模型文件的适配器和要引用的组件。

说明说明

Visual Studio ModelBus,您可以创建只对相同 Visual Studio 解决方案中的项目。

Ff519531.collapse_all(zh-cn,VS.110).gif导入显示的 DSL 程序集

在该使用的项目中,添加项目引用显示的 DSL 的 DSL 和 ModelBusAdapter 集。

例如,假定您在 MusicLibrary DSL 的元素若要存储 ModelBus 引用。ModelBus 引用将引用 FamilyTree DSL 的元素。在 MusicLibrary 解决方案的 Dsl 项目,在引用 " 节点,添加对以下程序集的引用:

  • Fabrikam.FamilyTree.Dsl.dll - 显示的 DSL。

  • Fabrikam.FamilyTree.ModelBusAdapters.dll - 显示的 DSL 的 ModelBus 适配器。

  • Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0

  • Microsoft.VisualStudio.Modeling.Sdk.Integration.Shell.11.0

这些程序集可在显示的 DSL 的 ModelBusAdapters 项目中找到,在 bin\*下。

在将要创建的代码文件引用,通常必须导入这些命名空间:

// The namespace of the DSL you want to reference:
using Fabrikam.FamilyTree;  // Exposed DSL
using Fabrikam.FamilyTree.ModelBusAdapters;
using Microsoft.VisualStudio.Modeling.Integration;
using System.Linq;
...

Ff519531.collapse_all(zh-cn,VS.110).gif创建对设计

若要创建设计引用,则访问显示的 DSL 的 AdapterManager,并用它来创建对该模型。可以指定文件路径或 EnvDTE.ProjectItem。

从 AdapterManager,可以获取适配器,提供对模型中的各个元素。

说明说明

,当您完成时,必须配置适配器。最方便的方式实现这一点与 using 语句。下面的示例阐释了这一点。

// The file path of a model instance of the FamilyTree DSL:
string targetModelFile = "TudorFamilyTree.ftree";
// Get the ModelBus service:
IModelBus modelBus = 
    this.Store.GetService(typeof(SModelBus)) as IModelBus;
// Get an adapterManager for the target DSL:
FamilyTreeAdapterManager manager = 
    (modelbus.GetAdapterManager(FamilyTreeAdapter.AdapterId) 
     as FamilyTreeAdapterManager;
// or: (modelBus.FindAdapterManagers(targetModelFile).First())
// or could provide an EnvDTE.ProjectItem

// Create a reference to the target model:
// NOTE: the target model must be a file in this project.
ModelBusReference modelReference =
     manager.CreateReference(targetModelFile);
// or can use an EnvDTE.ProjectItem instead of the filename

// Get the root element of this model:
using (FamilyTreeAdapter adapter = 
     modelBus.CreateAdapter(modelReference) as FamilyTreeAdapter)
{
  FamilyTree modelRoot = adapter.ModelRoot;
  // Access elements under the root in the usual way:
  foreach (Person p in modelRoot.Persons) {...}
  // You can create adapters for individual elements:
  ModelBusReference elementReference =
     adapter.GetElementReference(person);
  ...
} // Dispose adapter

如果希望以后可以使用 modelReference ,则可以使用外部类型 ModelBusReference的字段的特性可以将它存储:

using Transaction t = this.Store.TransactionManager
    .BeginTransaction("keep reference"))
{
  artist.FamilyTreeReference = modelReference;
  t.Commit();
}

若要允许用户编辑此字段属性,请使用 ModelReferenceEditor 作为参数在编辑属性。有关更多信息,请参见 允许用户编辑引用。

Ff519531.collapse_all(zh-cn,VS.110).gif创建对元素

为方式创建可用来创建的适配器和解析引用。

// person is an element in the FamilyTree model:
ModelBusReference personReference = 
  adapter.GetElementReference(person);

如果希望以后可以使用 elementReference ,则可以使用外部类型 ModelBusReference的字段的特性可以将它存储。若要允许用户编辑该文件,请使用 ModelElementReferenceEditor 作为参数在编辑属性。有关更多信息,请参见 允许用户编辑引用。

Ff519531.collapse_all(zh-cn,VS.110).gif解析引用

如果有 ModelBusReference (MBR) 可以获取该引用的设计或模型元素。如果元素在关系图或其他视图存在,您可以打开视图并选择该元素。

可以创建从 MBR 的适配器。从适配器,您可以获取该模型的根。还可以解决引用在模型中的特定元素的 MBR。

using Microsoft.VisualStudio.Modeling.Integration; ...
ModelBusReference elementReference = ...;

// Get the ModelBus service:
IModelBus modelBus = 
    this.Store.GetService(typeof(SModelBus)) as IModelBus;
// Use a model reference or an element reference
// to obtain an adapter for the target model:
using (FamilyTreeAdapter adapter = 
   modelBus.CreateAdapter(elementReference) as FamilyTreeAdapter)
   // or CreateAdapter(modelReference)
{
  // Get the root of the model:
  FamilyTree tree = adapter.ModelRoot;

  // Get a model element:
  MyDomainClass mel =
    adapter.ResolveElementReference<MyDomainClass>(elementReference);
  if (mel != null) {...}

  // Get the diagram or other view, if there is one:
  ModelBusView view = adapter.GetDefaultView();
  if (view != null) 
  {
   view.Open();
   // Display the diagram:
   view.Show(); 
   // Attempt to select the shape that presents the element:
   view.SetSelection(elementReference);
  }
} // Dispose the adapter.

若要解决 ModelBus 文本模板中引用

  1. 要访问的 DSL 必须为访问配置了从文本模板的 ModelBus 适配器。有关更多信息,请参见 To provide access to a DSL。

  2. 通常,可以访问目标 DSL 使用一辆模型总线在源 DSL 存储 Reference (MBR)。因此模板包含源 DSL 的指令,以及代码解决 MBR。有关文本模板的更多信息,请参见从域特定语言生成代码

    <#@ template debug="true" hostspecific="true" 
    inherits="Microsoft.VisualStudio.TextTemplating.Modeling.ModelBusEnabledTextTransformation" #> 
    <#@ SourceDsl processor="SourceDslDirectiveProcessor" requires="fileName='Sample.source'" #>
    <#@ output extension=".txt" #>
    <#@ assembly name = "Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0" #>
    <#@ assembly name = "System.Core" #>
    <#@ assembly name = "Company.CompartmentDragDrop.Dsl.dll" #>
    <#@ assembly name = "Company.CompartmentDragDrop.ModelBusAdapter.dll" #>
    <#@ import namespace="Microsoft.VisualStudio.Modeling.Integration" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="Company.CompartmentDragDrop" #>
    <#@ import namespace="Company.CompartmentDragDrop.ModelBusAdapters" #>
    <# // Get source root from directive processor:
      ExampleModel source = this.ExampleModel; 
      // This DSL has a MBR in its root:
    using (ModelBusAdapter adapter = this.ModelBus.CreateAdapter(source.ModelReference) as ModelBusAdapter) 
      {
      ModelBusAdapterManager manager = this.ModelBus.FindAdapterManagers(this.Host.ResolvePath("Sample.compDD1")).FirstOrDefault();
      ModelBusReference modelReference =
        manager.CreateReference(this.Host.ResolvePath("Sample.compDD1"));
    
      // Get the root element of this model:
      using (CompartmentDragDropAdapter adapter = 
         this.ModelBus.CreateAdapter(modelReference) as CompartmentDragDropAdapter)
      {
        ModelRoot root = adapter.ModelRoot;
    #>
    [[<#= root.Name #>]]
    <#
      }
    #>
    

有关更多信息和演练,请参见 在文本模板中使用 Visual Studio ModelBus

序列化 ModelBusReference

如果要存储 ModelBusReference (MBR) 以字符串的形式,因此,您可以序列化它:

string serialized = modelBus.SerializeReference(elementReference);
// Store it anywhere, then get it back again:
ModelBusReference elementReferenceRestored =
    modelBus.DeserializeReference(serialized, null);

这样序列化的 MBR 是上下文无关。如果使用简单的基于文件的模型总线适配器, MBR 包含绝对文件路径。,如果实例模型文件不会移动,这是不够的。但是,模型文件通常是在 Visual Studio 项目中。用户将所需可以移动整个项目移动到文件系统的不同部分。他们还需可以保留项目受源代码管理并打开它在不同的计算机上。序列化因此路径名称包含项目文件的位置。

Ff519531.collapse_all(zh-cn,VS.110).gif序列化相对于所指定的文件路径

ModelBusReference 包含 ReferenceContext,是字典可以存储信息 (如相对文件的路径序列化它。

序列化相对路径:

elementReference.ReferenceContext.Add(
   ModelBusReferencePropertySerializer.FilePathSaveContextKey, 
   currentProjectFilePath);
string serialized = modelBus.SerializeReference(elementReference);

从字符串检索引用:

ReferenceContext context = new ReferenceContext();
context.Add(ModelBusReferencePropertySerializer.FilePathLoadContextKey,
    currentProjectFilePath);
ModelBusReference elementReferenceRestored =
    modelBus.DeserializeReference(serialized, context);

Ff519531.collapse_all(zh-cn,VS.110).gifModelBusReferences 由其他适配器创建了

,如果要创建拥有适配器,以下信息很有用。

ModelBusReference (MBR) 由两部分组成:MBR 标题,使用模型总线对象并由特定适配器管理器处理的特定适配器。这使您可以提供拥有适配器序列化格式。例如,您可以引用数据库而不是文件,也可以在适配器可以存储附加信息引用。拥有适配器。 ReferenceContext能放在其他信息。

在反序列化 MBR 时,必须提供 ReferenceContext,在 MBR 对象并存储。在序列化 MBR 时,适配器用于存储的 ReferenceContext 帮助生成该字符串。该反序列化字符串。 ReferenceContext 不包含任何信息。例如,在简单的基于文件的适配器, ReferenceContext 包含根文件路径,在序列化 MBR 字符串不存储。

MBR 在两个阶段进行反序列化:

  • ModelBusReferencePropertySerializer 是相关 MBR 标头的标准序列化程序。它使用标准 DSL SerializationContext 属性包,使用关键 ModelBusReferencePropertySerializer.ModelBusLoadContextKey,在 ReferenceContext 存储。具体而言, SerializationContext 应包含 ModelBus实例。

  • ModelBus 适配器处理 MBR 的适配器特定部分。它可以使用在 MBR 的 ReferenceContext 存储的附加信息。使用键 FilePathLoadContextKey和 FilePathSaveContextKey,简单的基于文件的适配器保留根文件路径。

    ,仅当使用时,适配器在一个模型文件引用对象在。

创建模型

Ff519531.collapse_all(zh-cn,VS.110).gif创建,打开并编辑模型

以下片段在 VMSDK 网站上的系统示例中采用。它阐释 ModelBusReferences 创建并打开模型和关系图获取与模型。

在该示例中,目标 DSL 的名称为 StateMachine。多个名称从中派生,例如模型类的名称和 ModelBusAdapter 的名称。

using Fabrikam.StateMachine.ModelBusAdapters; 
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Integration;
using Microsoft.VisualStudio.Modeling.Integration.Shell;
using Microsoft.VisualStudio.Modeling.Shell;
...
// Create a new model.
ModelBusReference modelReference = 
   StateMachineAdapterManager    .CreateStateMachineModel(modelName, fileName);
//Keep reference of new model in this model.
using (Transaction t = ...)
{
  myModelElement.ReferenceProperty = modelReference;
  t.Commit();
}
// Get the ModelBus service from Visual Studio.
IModelBus modelBus = Microsoft.VisualStudio.Shell.Package.
    GetGlobalService(typeof(SModelBus)) as IModelBus;
// Get a modelbus adapter on the new model.
ModelBusAdapter modelBusAdapter;
modelBus.TryCreateAdapter(modelReference, 
    this.ServiceProvider, out modelBusAdapter);
using (StateMachineAdapter adapter = 
      modelBusAdapter as StateMachineAdapter)
{
    if (adapter != null)
    {
        // Obtain a Diagram from the adapter.
        Diagram targetDiagram = 
           ((StandardVsModelingDiagramView)
                 adapter.GetDefaultView()
            ).Diagram;

        using (Transaction t = 
             targetDiagram.Store.TransactionManager
                .BeginTransaction("Update diagram"))
        {
            DoUpdates(targetDiagram);
            t.Commit();
        }

        // Display the new diagram.
        adapter.GetDefaultView().Show();
    }
}

验证引用

BrokenReferenceDetector 在可保存 ModelBusReferences 的单元测试所有字段的特性。都会调用该事件提供的在何处查找所有事件。对于验证方法尤其有用。以下验证测试方法尝试的存储保存模型,并将报告中断在错误窗口中引用:

[ValidationMethod(ValidationCategories.Save)]
public void ValidateModelBusReferences(ValidationContext context)
{
  BrokenReferenceDetector.DetectBrokenReferences(this.Store,
    delegate(ModelElement element, // parent of property
             DomainPropertyInfo property, // identifies property
             ModelBusReference reference) // invalid reference
    { 
      context.LogError(string.Format(INVALID_REF_FORMAT, 
             property.Name, 
             referenceState.Name, 
             new ModelBusReferenceTypeConverter().
                 ConvertToInvariantString(reference)), 
         "Reference", 
         element);
      });
}}
private const string INVALID_REF_FORMAT = 
    "The '{0}' domain property of ths ReferenceState instance "
  + "named '{1}' contains reference value '{2}' which is invalid";

ModelBus 扩展执行的操作

,如果大量使用 ModelBus,以下信息并不重要,则为; 但是可能很有用。

ModelBus 扩展将在 DSL 解决方案进行以下更改。

在中右击 DSL 定义关系图时,请单击 启用 Modelbus,然后选择 使此 DSL 使用 ModelBus:

  • 在 DSL 项目,引用添加到 Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0.dll

  • 在 DSL 定义,外部类型引用添加的: Microsoft.VisualStudio.Modeling.Integration.ModelBusReference。

    可以在 DSL 资源管理器的引用,在 字段类型下。若要添加外部类型手动引用,右击根节点。

  • 新的模板文件添加, Dsl\GeneratedCode\ModelBusReferencesSerialization.tt

在设置字段的特性的类型。 ModelBusReference,然后时右击属性并单击 启用 ModelBusReference 特定属性:

  • 多种 CLR 特性添加到字段的特性。可在 " 属性 " 窗口中看到在自定义特性字段。在 Dsl\GeneratedCode\DomainClasses.cs,可以在属性声明的属性:

    [System.ComponentModel.TypeConverter(typeof(
    Microsoft.VisualStudio.Modeling.Integration.ModelBusReferenceTypeConverter))]
    [System.ComponentModel.Editor(typeof(
      Microsoft.VisualStudio.Modeling.Integration.Picker
      .ModelReferenceEditor // or ModelElementReferenceEditor
      ), typeof(System.Drawing.Design.UITypeEditor))]
    [Microsoft.VisualStudio.Modeling.Integration.Picker
      .SupplyFileBasedBrowserConfiguration
      ("Choose a model file", "Target model|*.target")]
    

在中右击 DSL 定义关系图时,请单击 启用 ModelBus,然后选择 显示此 DSL 在 ModelBus:

  • 新项目 ModelBusAdapter 添加到解决方案。

  • 为 ModelBusAdapter 的引用添加到 DslPackage 项目。ModelBusAdapter 具有对 Dsl 项目。

  • DslPackage\source.extention.tt, |ModelBusAdapter| 添加为 MEF 组件。

请参见

概念

如果:在程序代码中从文件打开模型

如何:将 UML 模型与其他模型和工具集成

如何:添加拖放处理程序

在文本模板中使用 Visual Studio ModelBus