Procedura: definire un gestore movimenti in un diagramma di modellazione

In Visual Studio Ultimate è possibile definire comandi che vengono eseguiti quando l'utente fa doppio clic sugli elementi o li trascina in un diagramma UML.È possibile comprimere queste estensioni in Visual Studio Integration Extension (VSIX) e distribuirlo ad altri utenti di Visual Studio Ultimate.

Se è già disponibile un comportamento predefinito per il tipo di diagramma e il tipo di elemento che si desidera trascinare, potrebbe non essere possibile aggiungere questo comportamento o eseguirne l'override.

Requisiti

Creazione di un gestore movimenti

Per definire un gestore movimenti per una finestra di progettazione UML, è necessario creare una classe che definisce il comportamento del gestore movimenti e incorporarla in un progetto VSIX (Visual Studio Integration Extension).Il progetto VSIX funge da contenitore per l'installazione del gestore.Esistono due metodi alternativi per definire un gestore movimenti:

  • Creazione di un gestore movimenti in un progetto VSIX distinto mediante un modello di progetto. Si tratta del metodo più rapido.Utilizzarlo se non si desidera combinare il gestore con altri tipi di estensione quali estensioni della convalida, elementi della casella degli strumenti personalizzati o gestori movimenti.

  • Creazione di progetti di gestori movimenti e progetti VSIX distinti. Utilizzare questo metodo se si desidera combinare più tipi di estensione nello stesso progetto VSIX.Ad esempio, se per il gestore movimenti è previsto che il modello osservi vincoli specifici, è possibile incorporarlo nello stesso progetto VSIX come un metodo di convalida.

Per creare un gestore movimenti in un progetto VSIX distinto

  1. Nella finestra di dialogo Nuovo progetto, sotto Progetti di modello fare clic su Estensione di movimento.

  2. Aprire il file con estensione .cs nel nuovo progetto e modificare la classe GestureExtension per implementare il gestore movimenti.

    Per ulteriori informazioni, vedere Implementazione del gestore movimenti.

  3. Testare il gestore movimenti premendo F5.Per ulteriori informazioni, vedere Esecuzione del gestore movimenti.

  4. Installare il gestore movimenti in un altro computer copiando il file bin\*\*.vsix compilato dal progetto.Per ulteriori informazioni, vedere Installazione del gestore movimenti.

Di seguito è riportata la procedura alternativa:

Per creare una libreria di classi separata (DLL) per il gestore movimenti

  1. Creare un progetto Libreria di classi, in una nuova soluzione Visual Studio o in una soluzione esistente.

    1. Dal menu File, scegliere Nuovo, Progetto.

    2. In Modelli installati espandere Visual Basic o Visual C#, quindi nella colonna centrale scegliere Libreria di classi.

  2. Aggiungere i riferimenti seguenti al progetto.

    Microsoft.VisualStudio.Modeling.Sdk.11.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

    System.Windows.Forms

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer - Se si estendono diagrammi livello, è necessario solo questo riferimento.Per ulteriori informazioni, vedere Estensione dei diagrammi livello.

  3. Aggiungere un file di classe al progetto e impostarne il contenuto sul codice seguente.

    [!NOTA]

    Modificare i nomi di spazio dei nomi e classi in base alle proprie preferenze.

    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
    using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Uml.Classes;
    // ADD other UML namespaces if required
    
    namespace MyGestureHandler // CHANGE
    {
      // DELETE any of these attributes if the handler
      // should not work with some types of diagram.
      [ClassDesignerExtension]
      [ActivityDesignerExtension]
      [ComponentDesignerExtension]
      [SequenceDesignerExtension]
      [UseCaseDesignerExtension]
      // [LayerDesignerExtension]
    
      // Gesture handlers must export IGestureExtension:
      [Export(typeof(IGestureExtension))]
      // CHANGE class name
      public class MyGesture1 : IGestureExtension
      {
        [Import]
        public IDiagramContext DiagramContext { get; set; }
    
        /// <summary>
        /// Called when the user double-clicks on the diagram
        /// </summary>
        /// <param name="targetElement"></param>
        /// <param name="diagramPointEventArgs"></param>
        public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target shape, if any. Null if the target is the diagram.
          IShape targetIShape = targetElement.CreateIShape();
    
          // Do something...
        }
    
        /// <summary>
        /// Called repeatedly when the user drags from anywhere on the screen.
        /// Return value should indicate whether a drop here is allowed.
        /// </summary>
        /// <param name="targetMergeElement">References the element to be dropped on.</param>
        /// <param name="diagramDragEventArgs">References the element to be dropped.</param>
        /// <returns></returns>
        public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target element, if any. Null if the target is the diagram.
          IShape targetIShape = targetMergeElement.CreateIShape();
    
          // This example allows drag of any UML elements.
          return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0;
        }
    
    
        /// <summary>
        /// Execute the action to be performed on the drop.
        /// </summary>
        /// <param name="targetDropElement"></param>
        /// <param name="diagramDragEventArgs"></param>
        public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
        }
    
        /// <summary>
        /// Retrieves UML IElements from drag arguments.
        /// Works for drags from UML diagrams.
        /// </summary>
        private IEnumerable<IElement> GetModelElementsFromDragEvent
                (DiagramDragEventArgs dragEvent)
        {
          //ElementGroupPrototype is the container for
          //dragged and copied elements and toolbox items.
          ElementGroupPrototype prototype =
             dragEvent.Data.
             GetData(typeof(ElementGroupPrototype))
                  as ElementGroupPrototype;
          // Locate the originals in the implementation store.
          IElementDirectory implementationDirectory =
             dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
    
          return prototype.ProtoElements.Select(
            prototypeElement =>
            {
              ModelElement element = implementationDirectory
                .FindElement(prototypeElement.ElementId);
              ShapeElement shapeElement = element as ShapeElement;
              if (shapeElement != null)
              {
                // Dragged from a diagram.
                return shapeElement.ModelElement as IElement;
              }
              else
              {
                // Dragged from UML Model Explorer.
                return element as IElement;
              }
            });
        }
    
      }
    }
    

    Per ulteriori informazioni su cosa inserire nei metodi, vedere Implementazione del gestore movimenti.

È necessario aggiungere il comando di menu a un progetto VSIX, che fungerà da contenitore per l'installazione del comando.Se si desidera, è possibile includere altri componenti nello stesso progetto VSIX.

Per aggiungere un gestore movimenti distinto a un progetto VSIX

  1. Questa routine non è necessaria se si è creato il comando di gestione movimenti con il suo VSIX.

  2. Creare un progetto VSIX, a meno che la soluzione non ne includa già uno.

    1. In Esplora soluzioni, scegliere dal menu di scelta rapida della soluzione Aggiungi, Nuovo progetto.

    2. In Modelli installati espandere Visual Basic o Visual C#, quindi selezionare Estensibilità.Nella colonna centrale scegliere Progetto VSIX.

  3. Impostare il progetto VSIX come progetto di avvio della soluzione.

    • In Esplora soluzioni, dal menu di scelta rapida del progetto VSIX, scegliere Imposta come progetto di avvio.
  4. In source.extension.vsixmanifest, aggiungere il progetto Libreria di classi del gestore movimenti come componente MEF.

    1. Nella scheda metadati, impostare un nome per il progetto VSIX.

    2. Nella scheda Installa destinazioni, impostare Visual Studio Premium e Ultimate come destinazioni.

    3. Nella scheda Asset, scegliere Nuovoe nella finestra di dialogo impostare:

      Tipo = Componente MEF

      Origine = Progetto nella soluzione corrente

      Progetto = Il progetto Libreria di classi

Esecuzione del gestore movimenti

A scopo di test, eseguire il gestore movimenti in modalità di debug.

Per testare il gestore movimenti

  1. Premere F5 oppure scegliere Avvia debug dal menu Debug.

    Verrà avviata un'istanza sperimentale di Visual Studio.

    Risoluzione dei problemi. Se non viene avviata una nuova istanza di Visual Studio:

    • Se si dispone di più progetti, verificare che il progetto VSIX sia impostato come progetto di avvio della soluzione.

    • In Esplora soluzioni, dal menu di scelta rapida dell'avvio o solamente dal progetto, scegliere Proprietà.Scegliere la scheda Debug nell'editor delle proprietà del progetto.Assicurarsi che la stringa nel campo Avvia programma esterno sia il percorso completo di Visual Studio, in genere:

      C:\Programmi\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe

  2. Nell'istanza sperimentale di Visual Studio aprire o creare un progetto di modello e un diagramma di modellazione.Utilizzare un diagramma appartenente a uno dei tipi elencati negli attributi della classe del gestore movimenti.

  3. Fare doppio clic in un punto qualsiasi del diagramma.Dovrebbe venire chiamato il gestore relativo al doppio clic.

  4. Trascinare un elemento da Esplora modelli UML nel diagramma.Dovrebbe venire chiamato il gestore relativo al trascinamento.

Risoluzione dei problemi: se il gestore movimenti non funziona, verificare gli aspetti seguenti:

  • Il progetto di gestore movimenti è elencato come componente MEF nell'elenco Contenuto in source.extensions.manifest nel progetto VSIX.

  • I parametri di tutti gli attributi Import ed Export sono validi.

  • Il metodo CanDragDrop non restituisce false.

  • Il tipo di diagramma di modello utilizzato (classi UML, di sequenza e così via) viene elencato come uno degli attributi della classe del gestore movimenti [ClassDesignerExtension], [SequenceDesignerExtension] e così via.

  • Non vi sono funzionalità predefinite già definite per questo tipo di elemento di destinazione ed eliminato.

Implementazione del gestore movimenti

Ee534033.collapse_all(it-it,VS.110).gifMetodi del gestore movimenti

La classe del gestore movimenti implementa ed esporta IGestureExtension.I metodi da definire sono i seguenti:

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Restituisce true per consentire all'elemento di origine a cui viene fatto riferimento in dragEvent di essere rilasciato in questa destinazione.

Questo metodo non deve apportare modifiche al modello.Deve funzionare rapidamente, in quanto viene utilizzato per determinare lo stato della freccia quando l'utente sposta il mouse.

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Aggiorna il modello in base all'oggetto di origine a cui viene fatto riferimento in dragEvent e alla destinazione.

Chiamato quando l'utente rilascia il mouse dopo un'operazione di trascinamento.

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target è la forma sui cui l'utente ha fatto doppio clic.

È possibile scrivere gestori che possono accettare non solo UML ma anche un'ampia varietà di altri elementi, ad esempio file, nodi in una visualizzazione della classe .NET, nodi di Esplora architettura e così via.L'utente può trascinare uno di questi elementi in un diagramma UML, purché venga scritto un metodo OnDragDrop in grado di decodificare il form serializzato degli elementi.I metodi di decodifica variano da un tipo di elemento all'altro.

I parametri di questi metodi sono i seguenti:

  • ShapeElement target.Forma o diagramma su cui l'utente ha trascinato un qualche elemento.

    ShapeElement è una classe nell'implementazione sottostante gli strumenti di modellazione UML.Per ridurre il rischio di collocare i diagrammi e il modello UML in uno stato incoerente, è consigliabile non utilizzare direttamente i metodi di questa classe.Al contrario, eseguire il wrapping dell'elemento in IShape, quindi utilizzare i metodi descritti in Procedura: visualizzare un modello nei diagrammi.

    • Per ottenere IShape:

      IShape targetIShape = target.CreateIShape(target);
      
    • Per ottenere l'elemento del modello impostato come destinazione dall'operazione di trascinamento o doppio clic:

      IElement target = targetIShape.Element;
      

      È possibile eseguire il cast di questo elemento a un tipo di elemento più specifico.

    • Per ottenere l'archivio modelli UML che contiene il modello UML:

      IModelStore modelStore = 
        targetIShape.Element.GetModelStore(); 
      
    • Per ottenere l'accesso all'host e al provider del servizio:

      target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
      
  • DiagramDragEventArgs eventArgs.Questo parametro fornisce il form serializzato dell'oggetto di origine di un'operazione di trascinamento:

    System.Windows.Forms.IDataObject data = eventArgs.Data;  
    

    È possibile trascinare elementi di molti tipi diversi in un diagramma, da parti diverse di Visual Studio o dal desktop di Windows.Tipi diversi di elemento sono codificati in modi diversi in IDataObject.Per estrarre da esso gli elementi, fare riferimento alla documentazione per il tipo appropriato di oggetto.

    Se l'oggetto di origine è un elemento UML trascinato da Esplora modelli UML o da un altro diagramma UML, fare riferimento a Procedura: ottenere elementi di modelli UML da IDataObject.

Ee534033.collapse_all(it-it,VS.110).gifScrittura del codice dei metodi

Per ulteriori informazioni sulla scrittura del codice per leggere e aggiornare il modello, vedere Programmazione con l'API UML.

Per informazioni sull'accesso alle informazioni sul modello in un'operazione di trascinamento, vedere Procedura: ottenere elementi di modelli UML da IDataObject.

Se si utilizza un diagramma di sequenza, vedere anche Procedura: modificare i diagrammi di sequenza tramite l'API UML.

Oltre ai parametri dei metodi, è inoltre possibile dichiarare una proprietà importata nella classe che fornisce accesso al modello e al diagramma corrente.

[Import] public IDiagramContext DiagramContext { get; set; }

La dichiarazione di IDiagramContext consente di scrivere codice nei metodi che sia in grado di accedere al diagramma, alla selezione corrente e al modello:

IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}

Per ulteriori informazioni, vedere Procedura: esplorare il modello UML.

Installazione e disinstallazione di un'estensione

È possibile installare un'estensione di Visual Studio sia nel computer in uso che in altri computer.

Per installare un'estensione

  1. Nel computer trovare il file .vsix compilato dal progetto VSIX.

    1. In Esplora soluzioni, dal menu di scelta rapida del progetto VSIX scegliere Apri cartella in Esplora risorse.

    2. Individuare il file bin\*\Progetto.vsix

  2. Copiare il file .vsix nel computer di destinazione in cui si desidera installare l'estensione.Si può trattare del computer in uso o di un altro computer.

    Nel computer di destinazione deve essere presente una delle versioni di Visual Studio specificata in source.extension.vsixmanifest.

  3. Nel computer di destinazione, aprire il file .vsix.

    Verrà visualizzato Visual Studio Extension Installer e verrà installata l'estensione.

  4. Avviare o riavviare Visual Studio.

Per disinstallare un'estensione

  1. Scegliere Gestione estensioni dal menu Strumenti.

  2. Espandere Estensioni installate.

  3. Selezionare l'estensione, quindi fare clic su Disinstalla.

Raramente, può verificarsi che un'estensione errata non venga caricata creando un rapporto nella finestra di errore. Tale estensione non viene però visualizzata in Gestione estensioni.In tal caso, è possibile rimuovere l'estensione eliminando il file da:

%LocalAppData%\Local\Microsoft\VisualStudio\11.0\Extensions

Esempio

Nell'esempio seguente viene illustrato come creare linee di vita in un diagramma sequenza, in base alle parti e alle porte di un componente, trascinato da un diagramma componente.

Per testarlo, premere F5.Verrà aperta un'istanza sperimentale di Visual Studio.In questa istanza aprire un modello UML e creare un componente in un diagramma componente.Aggiungere a questo componente alcune interfacce e parti di componente interne.Selezionare le interfacce e le parti.Trascinare quindi le interfacce e le parti su un diagramma di sequenza.Trascinare dal diagramma dei componenti alla scheda per il diagramma di sequenza e quindi verso il basso nel diagramma di sequenza. Verrà visualizzata una linea di vita per ogni interfaccia e parte.

Per ulteriori informazioni sull'associazione di interazioni ai diagrammi di sequenza, vedere Procedura: modificare i diagrammi di sequenza tramite l'API UML.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;

/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
  [Import]
  public IDiagramContext Context { get; set; }

  /// <summary>
  /// Called by the modeling framework when
  /// the user drops something on a target.
  /// </summary>
  /// <param name="target">The target shape or diagram </param>
  /// <param name="dragEvent">The item being dragged</param>
  public void OnDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    ISequenceDiagram diagram = Context.CurrentDiagram
            as ISequenceDiagram;
    IInteraction interaction = diagram.Interaction;
    if (interaction == null)
    {
      // Sequence diagram is empty: create an interaction.
      interaction = diagram.ModelStore.Root.CreateInteraction();
      interaction.Name = Context.CurrentDiagram.Name;
      diagram.Bind(interaction);
    }
    foreach (IConnectableElement connectable in
       GetConnectablesFromDrag(dragEvent))
    {
      ILifeline lifeline = interaction.CreateLifeline();
      lifeline.Represents = connectable;
      lifeline.Name = connectable.Name;
    }
  }

  /// <summary>
  /// Called by the modeling framework to determine whether
  /// the user can drop something on a target.
  /// Must not change anything.
  /// </summary>
  /// <param name="target">The target shape or diagram</param>
  /// <param name="dragEvent">The item being dragged</param>
  /// <returns>true if this item can be dropped on this target</returns>
  public bool CanDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
    return connectables.Count() > 0;
  }

  ///<summary>
  /// Get dragged parts and ports of an IComponent.
  ///</summary>
  private IEnumerable<IConnectableElement>
    GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
  {
    foreach (IElement element in
      GetModelElementsFromDragEvent(dragEvent))
    {
      IConnectableElement part = element as IConnectableElement;
      if (part != null)
      {
        yield return part;
      }
    }
  }

  /// <summary>
  /// Retrieves UML IElements from drag arguments.
  /// Works for drags from UML diagrams.
  /// </summary>
  private IEnumerable<IElement> GetModelElementsFromDragEvent
          (DiagramDragEventArgs dragEvent)
  {
    //ElementGroupPrototype is the container for
    //dragged and copied elements and toolbox items.
    ElementGroupPrototype prototype =
       dragEvent.Data.
       GetData(typeof(ElementGroupPrototype))
            as ElementGroupPrototype;
    // Locate the originals in the implementation store.
    IElementDirectory implementationDirectory =
       dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;

    return prototype.ProtoElements.Select(
      prototypeElement =>
      {
        ModelElement element = implementationDirectory
          .FindElement(prototypeElement.ElementId);
        ShapeElement shapeElement = element as ShapeElement;
        if (shapeElement != null)
        {
          // Dragged from a diagram.
          return shapeElement.ModelElement as IElement;
        }
        else
        {
          // Dragged from UML Model Explorer.
          return element as IElement;
        }
      });
  }

  public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
  {
  }
}

Il codice di GetModelElementsFromDragEvent() è descritto nell'argomento Procedura: ottenere elementi di modelli UML da IDataObject.

Vedere anche

Concetti

Procedura: definire e installare un'estensione di modellazione

Estensione di modelli e diagrammi UML

Procedura: definire un comando di menu in un diagramma di modellazione

Procedura: definire vincoli di convalida per i modelli UML

Programmazione con l'API UML