다음을 통해 공유


방법: 모양 또는 데코레이터 클릭 가로채기

다음 절차는 셰이프나 아이콘 데코레이터에 대 한 클릭을 가로채는 방법을 보여 줍니다.클릭 만으로 차단할 수, 두 번 클릭, 끌기 및 기타 제스처, 및 응답 요소를 합니다.

클릭할 때 셰이프가 차단 하기

Dsl 프로젝트에서 생성 된 코드 파일에서 별도 코드 파일에 셰이프 클래스에 대 한 partial 클래스 정의 작성 합니다.재정의 OnDoubleClick() 로 시작 하는 이름을 가진 다른 방법 중 하나 또는 On....예를 들면 다음과 같습니다.

public partial class MyShape // change
  {
    public override void OnDoubleClick(DiagramPointEventArgs e)
    {
      base.OnDoubleClick(e);
      System.Windows.Forms.MessageBox.Show("Click");
      e.Handled = true;
  }  }

[!참고]

설정 e.Handled 에 true, 이벤트를 포함 하는 도형 또는 다이어그램으로 전달 하지 않는.

클릭할 때 Decorators 차단 하기

이미지 decorators OnDoubleClick 메서드를 포함 하는 이미지 필드 클래스의 인스턴스를 전달 됩니다.이미지 필드 하는 서브 클래스를 작성 하는 경우에 조금을 가로챌 수 있습니다.필드의 InitializeShapeFields 메서드에서 설정 됩니다.따라서, 일반 이미지 필드 대신 하위 클래스를 인스턴스화하는 메서드를 변경 해야 합니다.Shape 클래스의 생성 된 코드에서 InitializeShapeFields 메서드를입니다.설정 하면 shape 클래스를 재정의할 수 있습니다 해당 Generates Double Derived 다음 절차에 설명 된 대로 속성입니다.

인스턴스 메서드 InitializeShapeFields 이지만, 각 클래스에 대해 한 번만 호출 됩니다.따라서, Clickableimagefield의 인스턴스를 하나만 각 셰이프는 다이어그램에서에 대 한 한 인스턴스 않습니다 각 클래스의 각 필드에 대 한 존재합니다.사용자 인스턴스를 두 번 클릭 하면 코드 예제에서와 같이 적중 된 인스턴스를를 식별 해야 합니다.

아이콘 데코레이터에 대 한 클릭을 가로채

  1. 열기 또는 DSL 솔루션을 만듭니다.

  2. 선택 또는 아이콘 데코레이터, 포함 된 셰이프를 만들고 도메인 클래스에 매핑하십시오.

  3. 파일에서 별도 코드 파일에는 GeneratedCode 폴더, 이미지 필드의 새 클래스를 만듭니다.

    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Modeling.Design;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace Fabrikam.MyDsl { // Change to your namespace
    internal class ClickableImageField : ImageField
    {
      // You can also override OnClick and so on.
      public override void OnDoubleClick(DiagramPointEventArgs e)
      {
        base.OnDoubleClick(e);
        // Work out which instance was hit.
        MyShape shapeHit = e.HitDiagramItem.Shape as MyShape;
        if (shapeHit != null)
        {
          MyDomainClass element = 
              shapeHit.ModelElement as MyDomainClass;
          System.Windows.Forms.MessageBox.Show(
             "Double click on shape for " + element.Name);
          // If we do not set Handled, the event will
          // be passed to the containing shape:
          e.Handled = true;
        }
      }
    
       public ClickableImageField(string fieldName)
         : base(fieldName)
       { }
    }
    

    Handled 이벤트가 있는 셰이프를 전달할 사용 하지 않으려면 true로 설정 해야 합니다.

  4. 다음과 같은 partial 클래스 정의 추가 하 여 해당 셰이프의 classs에서 InitializeShapeFields 메서드를 재정의 합니다.

    public partial class MyShape // change
    {
     protected override void InitializeShapeFields
          (IList<ShapeField> shapeFields)
     {
      base.InitializeShapeFields(shapeFields);
      // You can see the above method in MyShapeBase 
      // in the generated Shapes.cs
      // It has already added fields for the Icons.
      // So you will have to retrieve them and replace with your own.
      ShapeField unwantedField = shapeFields.First
          (field => field.Name == "IconDecorator1");
      shapeFields.Remove(unwantedField);
    
      // Now replicate the generated code from the base class 
      // in Shape.cs, but with your own image constructor.
      ImageField field2 = new ClickableImageField("IconDecorator1");      
      field2.DefaultImage = ImageHelper.GetImage(
        MyDslDomainModel.SingletonResourceManager
        .GetObject("MyShapeIconDecorator1DefaultImage"));
          shapeFields.Add(field2);
    }
    
  1. 솔루션을 빌드하고 실행합니다.

  2. 인스턴스 셰이프에 있는 아이콘을 두 번 누릅니다.테스트 메시지를 표시 합니다.

가로채 고 클릭 CompartmentShape 목록에 끌어 놓습니다.

다음 샘플에서 끌어 구획 셰이프의에서 항목 순서를 변경할 수가 있습니다.이 코드를 실행.

  1. 사용 하 여 새 DSL 솔루션을 만들는 클래스 다이어그램 솔루션 템플릿.

    구획 셰이프가 있는 솔루션을 직접 함께 작업할 수도 있습니다.이 코드는 도형으로 표시 모델 요소와 구획 목록 항목에 표시 된 요소는 포함 관계입니다 가정 합니다.

  2. 설정의 생성 이중 파생 된 구획 셰이프의 속성을 합니다.

  3. 파일에 다음이 코드를 추가 Dsl 프로젝트입니다.

  4. 도메인 클래스 및 셰이프 이름이 코드를 직접 DSL에 맞게 조정 합니다.

즉, 코드는 다음과 같이 작동 합니다.이 예제에서 ClassShape 구획 셰이프의 이름입니다.

  • 만들 때 마우스 이벤트 처리기 집합 각 구획 인스턴스에 연결 되어 있습니다.

  • ClassShape.MouseDown 이벤트의 현재 항목을 저장 합니다.

  • 마우스가 이동할 때 현재 항목의 Mouseaction의 인스턴스 생성, 커서를 설정 하 고 해제 될 때까지 마우스를 캡처합니다.

    마우스를 원래 항목 종료 될 때까지 선택 된 항목의 텍스트와 같은 다른 마우스 작업을 방해 하지 않도록 하 여 MouseAction 만들어지지 않습니다.

    여 MouseAction 만드는 대신 Mouseup에 대 한 수신 대기를 간단 하 게 됩니다.사용자가 외부 구획을 드래그 한 후 마우스를 놓을 경우 단,이 제대로 작동 하지 않습니다.여 MouseAction 마우스를 놓은 위치에 관계 없이 적절 한 작업을 수행할 수 있습니다.

  • 마우스를 놓으면 MouseAction.MouseUp 모델 요소 사이는 링크의 순서를 다시 정렬 합니다.

  • 역할 순서 변경 표시를 업데이트 하는 규칙을 발생 시킵니다.이 문제를 이미 정의 되어 있고 추가 코드가 필요 하지 않습니다.

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Design;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Collections.Generic;
using System.Linq;

// This sample allows users to re-order items in a compartment shape by dragging.

// This example is built on the "Class Diagrams" solution template of VMSDK (DSL Tools).
// You will need to change the following domain class names to your own:
// ClassShape = a compartment shape
// ClassModelElement = the domain class displayed using a ClassShape
// This code assumes that the embedding relationships 
// displayed in the compartments don't use inheritance 
// (don't have base or derived domain relationships).

namespace Company.CompartmentDrag
{
 /// <summary>
 /// Manage the mouse while dragging a compartment item.
 /// </summary>
 public class CompartmentDragMouseAction : MouseAction
 {
  private ModelElement sourceChild;
  private ClassShape sourceShape;
  private RectangleD sourceCompartmentBounds;

  public CompartmentDragMouseAction(ModelElement sourceChildElement, ClassShape sourceParentShape, RectangleD bounds)
   : base (sourceParentShape.Diagram)
  {
   sourceChild = sourceChildElement;
   sourceShape = sourceParentShape;
   sourceCompartmentBounds = bounds; // For cursor.
  }
   
  /// <summary>
  /// Call back to the source shape to drop the dragged item.
  /// </summary>
  /// <param name="e"></param>
  protected override void OnMouseUp(DiagramMouseEventArgs e)
  {
   base.OnMouseUp(e);
   sourceShape.DoMouseUp(sourceChild, e);
   this.Cancel(e.DiagramClientView);
   e.Handled = true;
  }

  /// <summary>
  /// Ideally, this shouldn't happen. This action should only be active
  /// while the mouse is still pressed. However, it can happen if you
  /// move the mouse rapidly out of the source shape, let go, and then 
  /// click somewhere else in the source shape.
  /// </summary>
  /// <param name="e"></param>
  protected override void OnMouseDown(DiagramMouseEventArgs e)
  {
   base.OnMouseDown(e);
   this.Cancel(e.DiagramClientView);
   e.Handled = false;
  }

  /// <summary>
  /// Display an appropriate cursor while the drag is in progress:
  /// Up-down arrow if we are inside the original compartment.
  /// No entry if we are elsewhere.
  /// </summary>
  /// <param name="currentCursor"></param>
  /// <param name="diagramClientView"></param>
  /// <param name="mousePosition"></param>
  /// <returns></returns>
  public override System.Windows.Forms.Cursor GetCursor(System.Windows.Forms.Cursor currentCursor, DiagramClientView diagramClientView, PointD mousePosition)
  {
   // If the cursor is inside the original compartment, show up-down cursor.
   return sourceCompartmentBounds.Contains(mousePosition) 
    ? System.Windows.Forms.Cursors.SizeNS // Up-down arrow.
    : System.Windows.Forms.Cursors.No;
  }
 }

 /// <summary>
 /// Override some methods of the compartment shape.
 /// *** GenerateDoubleDerived must be set for this shape in DslDefinition.dsl. ****
 /// </summary>
 public partial class ClassShape
 {
  /// <summary>
  /// Model element that is being dragged.
  /// </summary>
  private static ClassModelElement dragStartElement = null;
  /// <summary>
  /// Absolute bounds of the compartment, used to set the cursor.
  /// </summary>
  private static RectangleD compartmentBounds;

  /// <summary>
  /// Attach mouse listeners to the compartments for the shape.
  /// This is called once per compartment shape.
  /// The base method creates the compartments for this shape.
  /// </summary>
  public override void EnsureCompartments()
  {
   base.EnsureCompartments();
   foreach (Compartment compartment in this.NestedChildShapes.OfType<Compartment>())
   {
    compartment.MouseDown += new DiagramMouseEventHandler(compartment_MouseDown);
    compartment.MouseUp += new DiagramMouseEventHandler(compartment_MouseUp);
    compartment.MouseMove += new DiagramMouseEventHandler(compartment_MouseMove);
   }
  }


  /// <summary>
  /// Remember which item the mouse was dragged from.
  /// We don't create an Action immediately, as this would inhibit the
  /// inline text editing feature. Instead, we just remember the details
  /// and will create an Action when/if the mouse moves off this list item.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseDown(object sender, DiagramMouseEventArgs e)
  {
   dragStartElement = e.HitDiagramItem.RepresentedElements
     .OfType<ClassModelElement>().FirstOrDefault();
   compartmentBounds = e.HitDiagramItem.Shape.AbsoluteBoundingBox;
  }

  /// <summary>
  /// When the mouse moves away from the initial list item,
  /// but still inside the compartment, create an Action 
  /// to supervise the cursor and handle subsequent mouse events.
  /// Transfer the details of the initial mouse position to the Action.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseMove(object sender, DiagramMouseEventArgs e)
  {
   if (dragStartElement != null)
   {
    if (dragStartElement != e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault())
    {
     e.DiagramClientView.ActiveMouseAction = new CompartmentDragMouseAction(dragStartElement, this, compartmentBounds);
     dragStartElement = null;
    }
   }
  }

  /// <summary>
  /// User has released the mouse button. 
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseUp(object sender, DiagramMouseEventArgs e)
  {
    dragStartElement = null;
  }

  /// <summary>
  /// Forget the source item if mouse up occurs outside the
  /// compartment.
  /// </summary>
  /// <param name="e"></param>
  public override void OnMouseUp(DiagramMouseEventArgs e)
  {
   base.OnMouseUp(e);
   dragStartElement = null;
  }


  /// <summary>
  /// Called by the Action when the user releases the mouse.
  /// If we are still on the same compartment but in a different list item,
  /// move the starting item to the position of the current one.
  /// </summary>
  /// <param name="dragFrom"></param>
  /// <param name="e"></param>
  public void DoMouseUp(ModelElement dragFrom, DiagramMouseEventArgs e)
  {
   // Original or "from" item:
   ClassModelElement dragFromElement = dragFrom as ClassModelElement;
   // Current or "to" item:
   ClassModelElement dragToElement = e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault();
   if (dragFromElement != null && dragToElement != null)
   {
    // Find the common parent model element, and the relationship links:
    ElementLink parentToLink = GetEmbeddingLink(dragToElement);
    ElementLink parentFromLink = GetEmbeddingLink(dragFromElement);
    if (parentToLink != parentFromLink && parentFromLink != null && parentToLink != null)
    {
     // Get the static relationship and role (= end of relationship):
     DomainRelationshipInfo relationshipFrom = parentFromLink.GetDomainRelationship();
     DomainRoleInfo parentFromRole = relationshipFrom.DomainRoles[0];
     // Get the node in which the element is embedded, usually the element displayed in the shape:
     ModelElement parentFrom = parentFromLink.LinkedElements[0];

     // Same again for the target:
     DomainRelationshipInfo relationshipTo = parentToLink.GetDomainRelationship();
     DomainRoleInfo parentToRole = relationshipTo.DomainRoles[0];
     ModelElement parentTo = parentToLink.LinkedElements[0];

     // Mouse went down and up in same parent and same compartment:
     if (parentTo == parentFrom && relationshipTo == relationshipFrom)
     {
      // Find index of target position:
      int newIndex = 0;
      var elementLinks = parentToRole.GetElementLinks(parentTo);
      foreach (ElementLink link in elementLinks)
      {
       if (link == parentToLink) { break; }
       newIndex++;
      }

      if (newIndex < elementLinks.Count)
      {
       using (Transaction t = parentFrom.Store.TransactionManager.BeginTransaction("Move list item"))
       {
        parentFromLink.MoveToIndex(parentFromRole, newIndex);
        t.Commit();
       }
      }
     }
    }
   }
  }

  /// <summary>
  /// Get the embedding link to this element.
  /// Assumes there is no inheritance between embedding relationships.
  /// (If there is, you need to make sure you've got the relationship
  /// that is represented in the shape compartment.)
  /// </summary>
  /// <param name="child"></param>
  /// <returns></returns>
  ElementLink GetEmbeddingLink(ClassModelElement child)
  {
   foreach (DomainRoleInfo role in child.GetDomainClass().AllEmbeddedByDomainRoles)
   {
    foreach (ElementLink link in role.OppositeDomainRole.GetElementLinks(child))
    {
     // Just the assume the first embedding link is the only one.
     // Not a valid assumption if one relationship is derived from another.
     return link;
    }
   }
   return null;
  }
 }
}

참고 항목

참조

데코레이터의 속성

기타 리소스

변경 내용에 대한 대응 및 전파