Поделиться через


Практическое руководство. Реагирование на изменения в UML-модели

Пользователи могут написать код, выполняемый каждый раз, когда изменяется UML-модель Visual Studio. Он реагирует как на изменения, вносимые непосредственно пользователями, так и на изменения, вызванные другими расширениями Visual Studio.

Предупреждение

Эта функция не поддерживается API расширений UML напрямую.Поэтому приходится использовать несколько нетрадиционный подход.Необходимый код приведен в этом разделе.Однако в некоторых случаях могут возникать непредвиденные последствия.Кроме того, в будущих реализациях UML в Visual Studio описанные в этом разделе подходы могут перестать работать.

Для применения описанных в этом разделе подходов рекомендуется ознакомиться с пакетом SDK для визуализации и моделирования (VMSDK), с помощью которого реализованы средства UML. Дополнительные сведения см. в разделе Пакет SDK визуализации и моделирования — доменные языки.

Содержание раздела

  • Создание проекта расширения UML

  • События и правила

  • Определение событий

  • Пример. Выделение цветом классов на основе стереотипов с помощью событий

  • Определение правил

  • Пример. Выделение цветом классов на основе стереотипов с помощью правил

  • Пример. Ассоциации, которые по умолчанию являются двунаправленными

  • Базовые модели и модели представлений

Создание проекта расширения UML

Зачастую к расширению, для которого уже реализован обработчик команды или жеста, добавляется обработчик событий. В этом случае описанный здесь код можно добавить в тот же проект Visual Studio. Дополнительные сведения см. в разделах Практическое руководство. Определение команды меню на схеме моделирования и Практическое руководство. Определение обработчика перетаскивания и двойного щелчка на схеме моделирования.

Если требуется создать обработчик событий в отдельном расширении Visual Studio, сначала следует создать новый проект проверки UML. В диалоговом окне Новый проект щелкните Проекты моделирования и выберите Расширение проверки моделей. Либо можно выполнить процедуру Определение расширения проверки, описанную в разделе Практическое руководство. Определение ограничений проверки для моделей UML.

В проект необходимо добавить ссылки на следующие компоненты:

  • \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Uml.dll

  • Microsoft.VisualStudio.ArchitectureTools.Extensibility.dll

  • Microsoft.VisualStudio.Modeling.Sdk.10.0dll

  • Microsoft.VisualStudio.Modeling.Sdk.Diagrams.10.0.dll

  • Microsoft.VisualStudio.Uml.Interfaces.dll

События и правила

Пакет SDK для визуализации и моделирования поддерживает два основных метода определения изменений в хранилище.

  • Обработчик событий реагирует на изменение после завершения транзакции, в которой произошло изменение. Обработчики событий обычно используются для распространения изменений за пределы модели: в пользовательские интерфейсы, файлы или базы данных. Кроме того, можно написать обработчик событий, вносящий в модель дополнительные изменения в новой транзакции.

    Правило реагирует на изменение внутри транзакции, в которой произошло изменение. Обычно правила используются для распространения изменений внутри модели, например для обеспечения согласованности различных частей модели. Кроме того, можно написать правило, которое будет предотвращать недопустимое изменение, отменяя транзакцию.

Дополнительные сведения о транзакциях см. в разделе Практическое руководство. Связывание обновлений модели с использованием транзакций.

Определение обработчиков событий

Чтобы обработчик событий вызывался, когда происходит изменение, этот обработчик необходимо зарегистрировать. Необходимо зарегистрировать обработчик для каждого класса элемента, который требуется отслеживать, например для варианта использования или для действия. Его не требуется регистрировать для каждого экземпляра.

В приведенном ниже примере цвет класса UML задается в соответствии с применяемым пользователем стереотипом. Для событий создания и удаления экземпляра стереотипа регистрируются обработчики. Поскольку в этом примере используются обработчики событий, а не правила, обработчики вызываются после завершения транзакции, в которой произошло изменение стереотипа. Так как задание цвета также является изменением в хранилище VMSDK, оно должно выполняться во второй транзакции.

Кроме того, обработчики событий можно использовать для выполнения изменений за пределами хранилища.

Код приведенного ниже примера можно изменить, чтобы он реагировал на другие события. Ниже перечислены важные особенности этого кода:

  • для регистрации обработчиков событий используется API проверки. Рабочая среда проверки позволяет легко выполнить код при открытии модели. Но код фактически не выполняет проверку, а пользователю не нужно вызывать проверку для выполнения обновлений;

  • обработчики событий представляют собой методы, добавляемые к классу Store.EventManagerDirectory. Это класс Store соответствующей реализации VMSDK (DSL), а не класс ModelStore UML. Класс EventManagerDirectory имеет фиксированный набор словарей для различных типов событий, таких как ElementAdded и ElementDeleted;

  • чтобы зарегистрировать события, необходимо знать имя связи или класса реализации, которые требуется отслеживать. Эти классы определяются в библиотеке Microsoft.VisualStudio.Modeling.Uml.dll, поэтому имена классов можно увидеть при отслеживании свойств в отладчике. Эти члены класса можно привести к интерфейсам соответствующих типов, например к IClass или IStereotype. Список типов интерфейсов см. в разделе Типы элементов модели.

    В будущих выпусках имена классов реализации могут быть другими;

  • обработчики событий вызываются, когда пользователь выполняет команды Отменить и Повторить. Например, после события добавления команда "Отменить" вызовет событие удаления. Обработчик событий должен реагировать на эти события, если изменения распространяются за пределы хранилища. Но он не должен осуществлять изменения внутри хранилища в ответ на команды "Отменить" и "Повторить" и не должен вносить изменения при чтении модели из файла. Можно использовать конструкцию if (!store.InUndoRedoOrRollback && !store.InSerializationTransaction)...;

  • в примере показаны обработчики событий добавления и удаления объектов модели. Можно также создать обработчики событий изменения значений свойств. Дополнительные сведения см. в разделе Обработчики событий распространяют изменения за пределы модели;

  • более подробные сведения об этих событиях см. в разделе Обработчики событий распространяют изменения за пределы модели.

Пример. Выделение цветом классов на основании стереотипов с помощью событий

Для этого примера необходимо также добавить ссылку на System.Drawing.dll.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Drawing;
using System.Linq;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Profiles;
using Microsoft.VisualStudio.Uml.UseCases;

using Microsoft.VisualStudio.Uml.ModelStore; // in private assembly. Used for Get|IsElementDefinition()

namespace UmlEvents  // <<<< EDIT
{
/// <summary>
/// Wraps a UML model to add stereotype coloring.
/// </summary>
public partial class ColoringModelAdapter
{
  // This is the underlying DSL store, not the wrapping UML ModelStore:
  private Store store;

  /// <summary>
  /// This isn't actually validation. It's to couple this adapter to the model before we start.
  /// The validation package creates an instance of this class and then calls this method.
  /// See "Validation": https://msdn.microsoft.com/library/bb126413.aspx
  /// </summary>
  /// <param name="vcontext"></param>
  /// <param name="model"></param>
  [Export(typeof(System.Action<ValidationContext, object>))]
  [ValidationMethod(ValidationCategories.Open)]
  public void ConnectAdapterToModel(ValidationContext vcontext, IModel model)
  {
    // This is the underlying DSL store, not the wrapping UML ModelStore:
    store = (model as ModelElement).Store;

    // Add an event that triggers on creating a stereotype instance.
    // See "Event handlers": https://msdn.microsoft.com/library/bb126250.aspx
    DomainClassInfo siClass = store.DomainDataDirectory.FindDomainClass
      ("Microsoft.VisualStudio.Uml.Classes.StereotypeInstance");
    store.EventManagerDirectory.ElementAdded.Add(siClass,
      new EventHandler<ElementAddedEventArgs>(StereotypeInstanceAdded));

    // For the deletion, we need to trigger from the deleted link
    // between the stereotype instance and the model element - 
    // because after deletion we can't find the element from the stereotype instance.
    DomainRelationshipInfo linkToStereotypeClass = store.DomainDataDirectory.FindDomainRelationship
      ("Microsoft.VisualStudio.Uml.Classes.ElementHasAppliedStereotypeInstances");
    store.EventManagerDirectory.ElementDeleted.Add(linkToStereotypeClass,
      new EventHandler<ElementDeletedEventArgs>(StereotypeInstanceDeleted));

    // Add here handlers for other events.
  }

  /// <summary>
  /// Event handler called whenever a stereotype instance is linked to a uml model element.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void StereotypeInstanceAdded(object sender, ElementAddedEventArgs e)
  {
    // Don't handle changes in undo or load from file:
    if (store.InUndoRedoOrRollback || store.InSerializationTransaction) return;

    IStereotypeInstance si = e.ModelElement as IStereotypeInstance;
    IElement umlElement = si.Element;

     // Work only with the core model, not the views:
     if (!umlElement.IsElementDefinition()) return;

    // I'm only interested in coloring classes and interfaces:
    if (!(umlElement is IType)) return;

    Color? color = ColorForStereotype(si.Name);
    if (color.HasValue)
    {
      SetColorOfShapes(si.Element, color.Value);
    }
  }

  /// <summary>
  /// Called whenever a stereotype instance is deleted - well, actually, 
  /// when the link between the stereotype instance and the uml model element is deleted.
  /// Triggering on the link deletion allows us to get both ends.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void StereotypeInstanceDeleted(object sender, ElementDeletedEventArgs e)
  {
    // Don't handle changes in undo or load from file:
    if (store.InUndoRedoOrRollback || store.InSerializationTransaction) return;

    // Use the generic link type to avoid unearthing the UML implementation DLL:
    ElementLink elementToStereotypeLink = e.ModelElement as ElementLink;
    IElement umlElement = elementToStereotypeLink.LinkedElements[0] as IElement;
    IStereotypeInstance si = elementToStereotypeLink.LinkedElements[1] as IStereotypeInstance;

     // Work only with the core model, not the views:
     if (!umlElement.IsElementDefinition()) return;

    // We're here either because a stereotype is being un-applied,
    // or because the uml element is being deleted.
    // Don't bother if the element is being deleted:
    if ((umlElement as ModelElement).IsDeleting) return;

    // We're only interested in classes and interfaces:
    if (!(umlElement is IType)) return;

    // Because more than one stereotype can be applied to an element,
    // we should check to see if there are any remaining:
    Color newColor = Color.WhiteSmoke; // Default if there aren't.
    foreach (IStereotypeInstance remainingSi in umlElement.AppliedStereotypes)
    {
      Color? color = ColorForStereotype(remainingSi.Name);
      if (color.HasValue)
      {
        newColor = color.Value;
        break;
      }
    }
    SetColorOfShapes(umlElement, newColor);
  }

  private void SetColorOfShapes(IElement element, Color color)
  {
    foreach (IShape shape in element.Shapes())
    {
      shape.Color = color;
    }
  }

  /// <summary>
  /// This example deals only with a subset of the standard stereotypes.
  /// </summary>
  private Color? ColorForStereotype(string name)
  {
    switch (name)
    {
      case "focus": return Color.AliceBlue;
      case "auxiliary": return Color.Bisque;
      case "specification": return Color.OliveDrab;
      case "realization": return Color.LightSeaGreen;
      case "implementationClass": return Color.PaleGoldenrod;
    }
    return null;
  } 
}}

Определение правил

Пользователи могут определять правила для распространения изменений внутри хранилища VMSDK. Внесение изменения и применение правила происходят в рамках одной транзакции. Когда пользователь вызывает команду "Отменить", оба изменения отменяются вместе.

Недостаток предыдущего примера: использование обработчиков событий для изменения цветов фигур. Цвет также связывается с полем в хранилище VMSDK, следовательно такое изменение должно выполняться в рамках транзакции. Поэтому, если пользователь после применения стереотипа вызывает команду Отменить, изменение цвета отменяется, а применение стереотипа — нет. Чтобы отменить применение стереотипа, требуется выполнить еще одну команду Отменить. В некоторых случаях именно такое поведение и является требуемым, а в остальных распространение изменений можно осуществить в рамках одной транзакции, определив правила.

Правила меньше подходят для распространения изменений за пределы хранилища, поскольку они не вызываются, когда пользователь выполняет команду Отменить или Повторить.

Правило представляет собой класс, регистрируемый в диспетчере правил. Обычно при написании кода VMSDK правила регистрируются путем задания атрибута для класса и включения этого класса в список, который считывается при загрузке кода расширения. Но поскольку реализация UML уже откомпилирована, правила необходимо добавлять в диспетчер правил динамически. Приведенный в примере код во многом зависит от текущей реализации механизма управления правилами, который может измениться в будущих выпусках.

Чтобы добавить правило, требуется знать имена классов реализации. В будущих выпусках они могут измениться. Насколько это возможно, элементы следует приводить к типам API UML, таким как IClass или IProfile.

В примере показаны правила, обрабатывающие добавление и удаление объектов модели UML. Можно также создать правила, реагирующие на изменения свойств объектов. Дополнительные сведения см. в разделе Правила распространяют изменения в пределах модели.

Пример. Выделение цветом классов на основании стереотипов с помощью правил

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Drawing;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.UseCases; 

using Microsoft.VisualStudio.Uml.ModelStore; // in private assembly. Used for Get|IsElementDefinition()


namespace UmlRules
{
  class ColorByStereotype
  {
    /// <summary>
    /// Singleton wrappers: one per model.
    /// </summary>
    private static Dictionary<IPackage, ColorByStereotype > modelAdapters = 
        new Dictionary<IPackage, ColorByStereotype >();

    private class Wrapper
    {
      /// <summary>
      /// This isn't actually validation. 
      /// It sets up some store rules.
      /// The validation package creates an instance of this class and then calls this method.
      /// See "Validation": https://msdn.microsoft.com/library/bb126413.aspx
      /// </summary>
      /// <param name="vcontext"></param>
      /// <param name="model"></param>
      [Export(typeof(System.Action<ValidationContext, object>))]
      [ValidationMethod(ValidationCategories.Open)]
      private void ConnectAdapterToModel(ValidationContext vcontext, IModel model)
      {
        modelAdapters.Add(model, new ColorByStereotype (model));
      }
    }

    private IModel model;
    private Store store;
    private ColorByStereotype (IModel model)
    {
      this.model = model;
      // This is the underlying DSL store, not the wrapping UML ModelStore:
      store = (model as ModelElement).Store;

      SetRule<StereotypeInstanceAddedRule>(
        store.DomainDataDirectory.FindDomainClass(
          "Microsoft.VisualStudio.Uml.Classes.StereotypeInstance"));
      
      // For the deletion, we need to trigger from the deleted link
      // between the stereotype instance and the model element - 
      // because after deletion we can't find the element from the stereotype instance.
      
      SetRule<StereotypeInstanceDeletedRule>(
        store.DomainDataDirectory.FindDomainRelationship(
        "Microsoft.VisualStudio.Uml.Classes.ElementHasAppliedStereotypeInstances"));
    }

    /// <summary>
    /// Register a rule. 
    /// Normally, you set a rule by prefixing the rule class with 
    /// [RuleOn(typeof(TargetClass))]
    /// but we are setting up the rule at runtime, so must add
    /// the rules to the relevant dictionaries.
    /// </summary>
    /// <typeparam name="T">Rule class</typeparam>
    /// <param name="classInfo">Class or relationship to which to attach the rule.</param>
    private void SetRule<T>(DomainClassInfo classInfo) where T : Rule, new()
    {
      T rule = new T();
      rule.FireTime = TimeToFire.TopLevelCommit;

      System.Type tt = typeof(T);
      string ruleSet = (typeof(AddRule).IsAssignableFrom(tt)) ? "AddRules" :
        (typeof(ChangeRule).IsAssignableFrom(tt)) ? "ChangeRules" :
        (typeof(DeleteRule).IsAssignableFrom(tt)) ? "DeleteRules" :
        (typeof(DeletingRule).IsAssignableFrom(tt)) ? "DeletingRules" : "";

      // The rest of this method uses reflection to achieve the following:
      // store.RuleManager.RegisterRule(rule);
      // classInfo.AddRules.Add(rule);

      System.Reflection.BindingFlags privateBinding = 
          System.Reflection.BindingFlags.Instance 
        | System.Reflection.BindingFlags.NonPublic;
      System.Reflection.MethodInfo mi = 
        typeof(RuleManager).GetMethod("RegisterRule", privateBinding);
      mi.Invoke(store.RuleManager, new object[] { rule });

      store.RuleManager.EnableRule(typeof(T));

      System.Reflection.PropertyInfo pi = 
        typeof(DomainClassInfo).GetProperty(ruleSet, privateBinding);
      dynamic rules = pi.GetValue(classInfo, null);
      System.Type ruleListType = rules.GetType();
      System.Reflection.FieldInfo listpi = 
        ruleListType.GetField("list", privateBinding);
      dynamic list = listpi.GetValue(rules);
      System.Type listType = list.GetType();
      System.Reflection.MethodInfo addmi = listType.GetMethod("Add");
      addmi.Invoke(list, new object[] { rule });


      System.Reflection.MethodInfo resetRulesCache = 
        typeof(DomainClassInfo).GetMethod("ResetRulesCache", privateBinding);
      resetRulesCache.Invoke(classInfo, null);

    }

    #region Rules.
    private class StereotypeInstanceAddedRule : AddRule
    {
      public override void ElementAdded(ElementAddedEventArgs e)
      {
        base.ElementAdded(e);
        Store store = e.ModelElement.Store;
        // Don't handle load from file:
        if (store.InSerializationTransaction)
          return;

        IStereotypeInstance si = e.ModelElement as IStereotypeInstance;
        IElement umlElement = si.Element;
        
         // Work only with the core model, not the views:
         if (!umlElement.IsElementDefinition()) return;

        // I'm only interested in coloring classes and interfaces:
        if (!(umlElement is IType)) return;

        Color? color = ColorForStereotype(si.Name);
        if (color.HasValue)
        {
          SetColorOfShapes(si.Element, color.Value);
        }
      }
    }
    private class StereotypeInstanceDeletedRule : DeleteRule
    {
      public override void ElementDeleted(ElementDeletedEventArgs e)
      {
        base.ElementDeleted(e);
        Store store = e.ModelElement.Store;


        // Use the generic link type to avoid using the UML implementation DLL:
        ElementLink elementToStereotypeLink = e.ModelElement as ElementLink;
        IElement umlElement = elementToStereotypeLink.LinkedElements[0] as IElement;

         // Work only with the core model, not the views:
         if (!umlElement.IsElementDefinition()) return;

        // We're here either because a stereotype is being un-applied,
        // or because the uml element is being deleted.
        // Don't bother if the element is being deleted:
        if ((umlElement as ModelElement).IsDeleting) return;

        // We're only interested in classes and interfaces:
        if (!(umlElement is IType)) return;

        // Because more than one stereotype can be applied to an element,
        // we should check to see if there are any remaining:
        Color newColor = Color.WhiteSmoke; // Default if there aren't.
        foreach (IStereotypeInstance remainingSi in umlElement.AppliedStereotypes)
        {
          Color? color = ColorForStereotype(remainingSi.Name);
          if (color.HasValue)
          {
            newColor = color.Value;
            break;
          }
        }
        SetColorOfShapes(umlElement, newColor);
      }
    }

    /// <summary>
    /// Set the color of the shapes that display an element.
    /// </summary>
    /// <param name="element"></param>
    /// <param name="color"></param>
    private static void SetColorOfShapes(IElement element, Color color)
    {
      foreach (IShape shape in element.Shapes())
      {
        shape.Color = color;
      }
    }

    /// <summary>
    /// For this sample, we just deal with some of the standard stereotypes.
    /// </summary>
    /// <param name="name">Stereotype name</param>
    /// <returns></returns>
    private static Color? ColorForStereotype(string name)
    {
      switch (name)
      {
        case "focus": return Color.AliceBlue;
        case "auxiliary": return Color.Bisque;
        case "specification": return Color.OliveDrab;
        case "realization": return Color.LightSeaGreen;
        case "implementationClass": return Color.PaleGoldenrod;
      }
      return null;
    }
    #endregion
  }
}

Пример. Ассоциации, которые по умолчанию являются двунаправленными

По умолчанию при создании на схеме классов ассоциации переход по такой ассоциации возможен только в одном направлении. Стрелка у нее имеется только на одном конце. Иногда бывает удобнее рисовать двунаправленные ассоциации без стрелок. Ассоциации можно по умолчанию делать двунаправленными, если добавить следующее правило.

/// <summary>
/// Rule invoked when an Association is created.
/// This rule sets both ends navigable, which is convenient for representing requirements.
/// </summary>
private class AssociationAddRule : AddRule
{
  public override void ElementAdded(ElementAddedEventArgs e)
  {
    Store store = e.ModelElement.Store;
    IAssociation association = e.ModelElement as IAssociation;

    // Do not apply the rule if we are reading from file or undoing a deletion:
    if (association.MemberEnds.Count() == 0 
       || store.InSerializationTransaction || store.InUndoRedoOrRollback) return;

    // Do not apply the rule unless a containing package or model has imported 
    // a profile that defines the stereotype "Default Binary Associations" for associations:
    // if (!association.ApplicableStereotypes.Any
    //      (s => s.DisplayName == "Default Binary Associations")) return;

    // Don’t apply the rule to use cases:
    if (!(association.SourceElement is IUseCase && association.TargetElement is IUseCase))
    {
      association.OwnedEnds.First().SetNavigable(true);
      association.OwnedEnds.Last().SetNavigable(true);
    }
  }
}

Чтобы зарегистрировать правило, необходимо воспользоваться методом SetRule, описанным в разделе Определение правил.

SetRule<AssociationAddRule>(store.DomainDataDirectory.
      FindDomainRelationship("Microsoft.VisualStudio.Uml.Classes.Association"));

Если требуется возможность включения или отключения этого правила, можно определить профиль, в котором будет определен конкретный стереотип. В правило можно добавить код, который будет проверять, включен ли профиль в соответствующем пакете или модели. Дополнительные сведения см. в разделе Практическое руководство. Определение профиля для расширения UML.

Базовые модели и модели представлений

Модель UML состоит из нескольких моделей VMSDK (DSL):

  • базовая модель содержит представления всех элементов модели UML. Пользователь может видеть эти элементы в окне обозревателя моделей UML, а разработчик может обращаться к ним с помощью API UML ModelStore. Базовая модель занимает один раздел хранилища VMSDK;

  • для каждой схемы UML в проекте UML имеется одна модель представлений. Объекты в каждой модели представлений представляют объекты базовой модели. Для каждого элемента, отображаемого на схеме UML, существует объект модели представлений. Каждая модель представлений занимает один раздел хранилища VMSDK;

  • для каждого элемента, отображаемого на схеме, существует объект фигуры VMSDK. Между фигурами и элементами модели представления имеется взаимно-однозначное соответствие.

Правила и обработчики событий вызываются как при изменении базовых объектов, так и при изменении объектов представления. Обрабатываться должны только изменения базовых объектов. В приведенных примерах обработчики используют метод element.IsElementDefinition(), чтобы проверять, обрабатывается ли именно базовый объект.

Чтобы использовать этот метод, необходимо добавить ссылку проекта на

%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Uml.dll

Предупреждение

IsElementDefinition и другие методы, определенные в закрытой сборке, могут измениться в следующих выпусках.

using Microsoft.VisualStudio.Uml.ModelStore; 
  // in private assembly. Used for GetElementDefinition()
...
  // Determine whether an element is view or core:
  if (anElement.IsElementDefinition()) 
  { /* core */ }
  else
  { /* view */ }
...
  // If shapeElement is a shape on a diagram -
  // The VMSDK element connected to the shape is in the view:
  IElement viewModelElement = shapeElement.ModelElement as IElement;
  // Get the core element for which the view is a proxy:
  IElement coreModelElement = viewModelElement.GetElementDefinition();
...

См. также

Задачи

Обработчики событий распространяют изменения за пределы модели

Основные понятия

Практическое руководство. Навигация по UML-модели

Другие ресурсы

Sample: Color by Stereotype

Журнал изменений

Дата

Журнал

Причина

Март 2011

Создан раздел.

Обратная связь от клиента.