방법: UML 모델의 변경 내용에 응답

업데이트: 2011년 3월

Visual Studio의 UML에 모델에 변경이 발생할 때마다 실행되는 코드를 작성할 수 있습니다. 이 코드는 사용자가 직접 수행한 변경 및 다른 Visual Studio 확장에서 수행한 변경에 대해 동일하게 응답합니다.

경고

UML 확장 API에서는 이 기능이 직접 지원되지 않습니다. 따라서 약간 특별한 방법을 사용해야 합니다. 필요한 코드는 이 항목에 제공됩니다. 하지만 경우에 따라 예기치 않은 결과가 발생할 수 있습니다. 또한 이후에 UML의 Visual Studio 구현이 변경되어 이 항목에서 설명한 방법을 사용하지 못하게 될 수도 있습니다.

이 항목에서 설명한 방법을 사용하려면 VMSDK(Visualization and Modeling SDK) 및 구현할 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

이벤트 및 규칙

VMSDK는 저장소의 변경을 감지하는 두 가지 보안 주체(principal) 메서드를 제공합니다.

  • 이벤트 처리기는 변경이 발생한 트랜잭션이 종료되면 변경에 응답합니다. 이벤트 처리기는 일반적으로 모델 외부의 변경을 사용자 인터페이스, 파일 또는 데이터베이스로 전파하는 데 사용됩니다. 새 트랜잭션의 모델에 추가 변경을 수행하는 이벤트 처리기를 작성할 수도 있습니다.

    규칙은 변경이 발생한 트랜잭션 내의 변경에 응답합니다. 일반적으로 규칙은 모델의 두 부분 간에 일관성을 유지하기 위해 모델 내부의 변경을 전파하는 데 사용됩니다. 트랜잭션을 취소하여 유효하지 않은 변경을 방지하는 규칙을 작성할 수도 있습니다.

트랜잭션에 대한 자세한 내용은 방법: 트랜잭션을 사용하여 모델 업데이트 연결을 참조하십시오.

이벤트 처리기 정의

변경이 발생할 때 이벤트 처리기를 호출하려면 이벤트 처리기를 등록해야 합니다. UseCase 또는 Activity 등과 같이 모니터링하려는 각 요소 클래스에 대해 처리기를 등록해야 합니다. 각 인스턴스에 대해 등록할 필요는 없습니다.

다음 예제에서는 사용자가 적용하는 스테레오타입에 따라 UML 클래스의 색상을 설정합니다. 이 이벤트 처리기는 스테레오타입 인스턴스가 생성되거나 삭제될 때마다 트리거되도록 등록됩니다. 이 예제에서는 규칙이 아닌 이벤트 처리기를 사용하기 때문에 스테레오타입이 변경되는 트랜잭션이 완료된 후 처리기가 호출됩니다. 색상도 VMSDK 저장소 내의 변경이기 때문에 두 번째 트랜잭션에서 수행되어야 합니다.

이벤트 처리기를 사용하여 저장소 외부에서 변경을 수행할 수도 있습니다.

원하는 이벤트에 응답하도록 다음 예제의 코드를 필요에 따라 적용할 수 있습니다. 단, 이 코드에 대한 다음 내용을 알아 두어야 합니다.

  • 유효성 검사 API는 이벤트 처리기를 등록하는 데 사용됩니다. 유효성 검사 프레임워크는 모델을 열 때 코드를 실행하는 편리한 방법입니다. 하지만 이 코드는 실제로 유효성 검사를 수행하지 않으며, 사용자가 업데이트를 수행하기 위해 유효성 검사를 호출할 필요가 없습니다.

  • 이벤트 처리기는 Store.EventManagerDirectory에 추가되는 메서드입니다. 이 메서드는 UML ModelStore가 아닌 기본 VMSDK(DSL)의 Store입니다. 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 구현은 이미 컴파일되었기 때문에 규칙을 규칙 관리자에 동적으로 추가해야 합니다. 이 예제의 코드는 현재 구현 규칙 관리를 사용하기 때문에 이후 릴리스에서 변경될 수 있습니다.

규칙을 추가하려면 구현 클래스의 이름을 알아야 합니다. 이러한 이름은 이후 릴리스에서 변경될 수 있습니다. 가능할 경우 IClass, IProfile 등과 같은 UML API 형식에 요소를 캐스팅해야 합니다.

다음 예제에서는 XML 모델에서 개체 추가 및 삭제를 처리하는 규칙을 보여 줍니다. 개체 속성의 변경에 응답하는 규칙을 만들 수도 있습니다. 자세한 내용은 규칙으로 모델 내부의 변경 내용 전파을 참조하십시오.

예제: 규칙을 사용하여 스테레오타입별로 클래스 색상 설정

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 모델 탐색기 창에서 이러한 요소를 볼 수 있으며 UML ModelStore API를 통해 이러한 요소에 액세스할 수 있습니다. 코어 모델은 하나의 VMSDK 저장소 파티션을 차지합니다.

  • UML 프로젝트에 있는 UML 다이어그램별로 하나의 뷰 모델이 있습니다. 각 뷰 모델의 개체는 코어 모델에 있는 개체에 대한 프록시입니다. UML 다이어그램에 표시되는 각 요소별로 하나의 뷰 모델 개체가 있습니다. 각 뷰 모델은 하나의 VMSDK 저장소 파티션을 차지합니다.

  • 다이어그램에 표시되는 각 요소별로 하나의 VMSDK 도형 개체가 있습니다. 뷰 모델 요소와 도형 간에는 1:1 관계가 형성됩니다.

규칙이나 이벤트 처리기를 정의하면 코어 및 뷰 개체가 변경될 때 호출됩니다. 사용자는 코어 개체에 대한 변경만 처리해야 합니다. 이 예제의 처리기는 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년 3월

항목을 작성했습니다.

고객 의견