Condividi tramite


Procedura: intercettare un clic su una forma o su un elemento Decorator

Le procedure riportate di seguito illustrano come intercettare un clic su un form o su un elemento Decorator icona.È possibile intercettare i clic, fare doppio clic su, trascinamento e altri movimenti e preparato l'elemento rispondere.

Per intercettare fa clic su forme

In il progetto di Dsl, in un file di codice che è separato da file di codice generati, scrivere una definizione di classe parziale per la classe della forma.Eseguire l'override di OnDoubleClick() o uno degli altri metodi che hanno un nome a partire da On...Di seguito è riportato un esempio:

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

[!NOTA]

Impostare e.Handled a true, a meno che non si desideri che l'evento da passare alla forma o al diagramma contenitore.

Per intercettare fa clic sugli elementi Decorator

Gli elementi Decorator di immagini sono portati in un'istanza della classe di ImageField, che ha un metodo di un OnDoubleClick.È possibile intercettare i clic su se si scrive una sottoclasse di ImageField.I campi sono configurati nel metodo di InitializeShapeFields.Pertanto, è necessario modificare il metodo per creare un'istanza della sottoclasse anziché ImageField normale.Il metodo di InitializeShapeFields al codice generato della classe della forma.È possibile eseguire l'override della classe di forma se si imposta la proprietà di Generates Double Derived come descritto nella procedura riportata di seguito.

Sebbene InitializeShapeFields è un metodo di istanza, viene chiamato una volta per ogni classe.Di conseguenza, una sola istanza di ClickableImageField esiste per ogni campo in ogni classe, non un'unica istanza per ogni forma del diagramma.Quando l'utente fa doppio clic su un'istanza, è necessario identificare quali l'istanza raggiunta, come illustrato nel codice riportato nell' esempio seguente.

Per intercettare un clic su un elemento Decorator icona

  1. Aprire o creare una soluzione DSL.

  2. Scegliere o creare una forma con un elemento Decorator icona ed eseguirne il mapping a una classe di dominio.

  3. In un file di codice che è separato dai file nella cartella di GeneratedCode , creare una nuova sottoclasse di ImageField:

    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)
       { }
    }
    

    È necessario impostare gestito su true se non si desidera che l'evento da passare alla forma contenitore.

  4. Eseguire l'override del metodo di InitializeShapeFields in classs shape aggiungendo la seguente definizione di classe parziale.

    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. Compilare ed eseguire la soluzione.

  2. Fare doppio clic sull' icona in un'istanza della forma.Il messaggio di testo visualizzato.

L'intercettazione fare clic su e si trascinano gli elenchi di CompartmentShape

Il seguente esempio consente agli utenti riordinino gli elementi in una forma del raggruppamento trascinandoli.Per eseguire questo codice:

  1. Creare una nuova soluzione DSL utilizzando il modello della soluzione di diagrammi classi .

    È possibile utilizzare una soluzione di diventi proprietaria contenente le forme di raggruppamento.In questo codice si presuppone che sia presente una relazione che utilizza tra elementi del modello rappresentati dalla forma e gli elementi rappresentati negli elementi dell' elenco di raggruppamento.

  2. Impostare la proprietà di genera il doppio derivato della forma del raggruppamento.

  3. Aggiungere questo codice in un file nel progetto Dsl .

  4. Modificare i nomi di forma e la classe di dominio nel codice per la corrispondenza per contenere il modello DSL.

In breve, che il codice come segue.In questo esempio, ClassShape è il nome della forma del raggruppamento.

  • Un set di gestori eventi del mouse è associato a ogni istanza del raggruppamento quando viene creata.

  • l'evento di ClassShape.MouseDown archivia l'elemento corrente.

  • Quando il mouse si sposta l'elemento corrente, un'istanza di MouseAction viene creata, che imposta il cursore e acquisisce il mouse fino a rilasciarlo.

    Per evitare interferire con le azioni del mouse, come selezionare il testo di un elemento, il MouseAction non vengono creati finché il mouse non ha lasciato l'elemento originale.

    Un'alternativa alla creazione di un MouseAction sarebbe sufficiente di rimanere in ascolto MouseUp.Tuttavia, questo non verrà eseguita correttamente se l'utente rilascia il mouse dopo avere trascinatolo all' esterno del contesto.Il MouseAction possibile eseguire l'azione appropriata quando il mouse viene rilasciato.

  • Quando il mouse viene rilasciato, MouseAction.MouseUp ridisporre l'ordine dei collegamenti tra elementi del modello.

  • La modifica del ruolo dell' ordine genera una regola che aggiorna la visualizzazione.Questo comportamento è già definito e non esiste alcun codice aggiuntivo richiesto.

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;
  }
 }
}

Vedere anche

Riferimenti

Proprietà degli elementi Decorator

Altre risorse

Risposta alle modifiche e propagazione delle modifiche