Condividi tramite


Personalizzazione della creazione e dello spostamento di elementi

È possibile consentire il trascinamento di un elemento in un altro elemento, dalla casella degli strumenti o in un'operazione incolla o di spostamento. È possibile che gli elementi spostati siano collegati agli elementi di destinazione, usando le relazioni specificate.

Una direttiva di merge degli elementi (EMD) specifica cosa accade quando un elemento del modello viene unito in un altro elemento del modello. Ciò si verifica quando:

  • L'utente trascina dalla casella degli strumenti nel diagramma o in una forma.

  • L'utente crea un elemento utilizzando un menu Aggiungi nella finestra di esplorazione o in una forma di raggruppamento.

  • L'utente sposta un elemento da una corsia a un'altra.

  • L'utente incolla un elemento.

  • Il codice del programma chiama la direttiva merge degli elementi.

Anche se le operazioni di creazione potrebbero sembrare diverse dalle operazioni di copia, funzionano effettivamente nello stesso modo. Quando viene aggiunto un elemento, ad esempio dalla casella degli strumenti, viene replicato un prototipo di esso. Il prototipo viene unito al modello nello stesso modo degli elementi copiati da un'altra parte del modello.

La responsabilità di un EMD è decidere in che modo un oggetto o un gruppo di oggetti deve essere unito in una determinata posizione nel modello. In particolare, determina le relazioni di cui creare un'istanza per collegare il gruppo unito al modello. È anche possibile personalizzarlo per impostare le proprietà e per creare oggetti aggiuntivi.

Diagram showing a before and after look at a tree of elements and their reference relationships when An E M D determines how a new element is added.

Un EMD viene generato automaticamente quando si definisce una relazione di incorporamento. Questo EMD predefinito crea un'istanza della relazione quando gli utenti aggiungono nuove istanze figlio all'elemento padre. È possibile modificare questi EMD predefiniti, ad esempio aggiungendo codice personalizzato.

È anche possibile aggiungere i propri EMD nella definizione DSL per consentire agli utenti di trascinare o incollare diverse combinazioni di classi unite e riceventi.

Definizione di una direttiva merge di elementi

È possibile aggiungere direttive di merge degli elementi alle classi di dominio, alle relazioni di dominio, alle forme, ai connettori e ai diagrammi. È possibile aggiungerli o trovarli in Esplora DSL nella classe di dominio ricevente. La classe ricevente è la classe di dominio dell'elemento già presente nel modello e in cui verrà unito l'elemento nuovo o copiato.

Screenshot of DSL Explorer showing an E M D being added with ExampleElement selected as the Indexing class and the Applies to subclasses option checked.

La classe indexing è la classe di dominio di elementi che possono essere uniti ai membri della classe ricevente. Anche le istanze delle sottoclassi della classe di indicizzazione verranno unite da questo EMD, a meno che non si imposti Si applica alle sottoclassi su False.

Esistono due tipi di direttiva merge:

  • Una direttiva Process Merge specifica le relazioni in base alle quali il nuovo elemento deve essere collegato all'albero.

  • Una direttiva Forward Merge reindirizza il nuovo elemento a un altro elemento ricevente, in genere un elemento padre.

È possibile aggiungere codice personalizzato alle direttive di merge:

  • Imposta Usa accetta personalizzata per aggiungere codice personalizzato per determinare se una determinata istanza dell'elemento di indicizzazione deve essere unita all'elemento di destinazione. Quando l'utente trascina dalla casella degli strumenti, il puntatore "non valido" indica se il codice non consente l'unione.

    Ad esempio, è possibile consentire l'unione solo quando l'elemento ricevente si trova in uno stato specifico.

  • Imposta Usa unione personalizzata per aggiungere codice personalizzato per definire le modifiche apportate al modello quando viene eseguita l'unione.

    Ad esempio, è possibile impostare le proprietà nell'elemento unito usando i dati della nuova posizione nel modello.

Nota

Se si scrive codice di merge personalizzato, influisce solo sulle unioni eseguite usando questo EMD. Se sono presenti altri EMD che uniscono lo stesso tipo di oggetto o se è presente un altro codice personalizzato che crea questi oggetti senza usare EMD, non saranno interessati dal codice di unione personalizzato.

Se si vuole assicurarsi che un nuovo elemento o una nuova relazione venga sempre elaborato dal codice personalizzato, è consigliabile definire un elemento AddRule nella relazione di incorporamento e un oggetto DeleteRule nella classe di dominio dell'elemento. Per altre informazioni, vedere Regole propagate modifiche all'interno del modello.

Esempio: Definizione di un EMD senza codice personalizzato

L'esempio seguente consente agli utenti di creare un elemento e un connettore contemporaneamente trascinando dalla casella degli strumenti in una forma esistente. Nell'esempio viene aggiunto un EMD alla definizione DSL. Prima di questa modifica, gli utenti possono trascinare gli strumenti nel diagramma, ma non nelle forme esistenti.

Gli utenti possono anche incollare elementi in altri elementi.

Per consentire agli utenti di creare un elemento e un connettore contemporaneamente

  1. Creare un nuovo linguaggio DSL usando il modello di soluzione Linguaggio minimo.

    Quando si esegue questo linguaggio DSL, è possibile creare forme e connettori tra le forme. Non è possibile trascinare una nuova forma ExampleElement dalla casella degli strumenti in una forma esistente.

  2. Per consentire agli utenti di unire elementi in ExampleElement forme, creare un nuovo EMD nella ExampleElement classe di dominio:

    1. In Esplora DSL espandere Classi di dominio. Fare clic con il pulsante destro del mouse ExampleElement e quindi scegliere Aggiungi nuova direttiva unione elemento.

    2. Assicurarsi che la finestra Dettagli DSL sia aperta, in modo che sia possibile visualizzare i dettagli del nuovo EMD. (Menu: View, Other Windows, DSL Details.)

  3. Impostare la classe Indexing nella finestra Dettagli DSL per definire la classe di elementi che è possibile unire agli ExampleElement oggetti.

    Per questo esempio, selezionare , in modo che l'utente possa trascinare ExampleElementsnuovi elementi in elementi esistenti.

    Si noti che la classe Indexing diventa il nome dell'EMD in Esplora DSL.

  4. In Processo di unione creando collegamenti aggiungere due percorsi:

    • Un percorso collega il nuovo elemento al modello padre. L'espressione di percorso che è necessario immettere passa dall'elemento esistente, fino alla relazione di incorporamento al modello padre. Specifica infine il ruolo nel nuovo collegamento a cui verrà assegnato il nuovo elemento. Il percorso è il seguente:

      ExampleModelHasElements.ExampleModel/!ExampleModel/.Elements

    • L'altro percorso collega il nuovo elemento all'elemento esistente. L'espressione di percorso specifica la relazione di riferimento e il ruolo a cui verrà assegnato il nuovo elemento. Questo percorso è il seguente:

      ExampleElementReferencesTargets.Sources

      È possibile usare lo strumento di spostamento percorso per creare ogni percorso:

      1. In Processo unione creando collegamenti nei percorsi fare clic su <Aggiungi percorso>.

      2. Fare clic sulla freccia a discesa a destra dell'elemento di elenco. Viene visualizzata una visualizzazione albero.

      3. Espandere i nodi nell'albero per formare il percorso da specificare.

  5. Testare il linguaggio DSL:

    1. Premere F5 per ricompilare ed eseguire la soluzione.

      La ricompilazione richiederà più tempo del solito perché il codice generato verrà aggiornato dai modelli di testo per essere conforme alla nuova definizione DSL.

    2. All'avvio dell'istanza sperimentale di Visual Studio, aprire un file di modello del linguaggio DSL. Creare alcuni elementi di esempio.

    3. Trascinare dallo strumento Elemento di esempio in una forma esistente.

      Viene visualizzata una nuova forma ed è collegata alla forma esistente con un connettore.

    4. Copiare una forma esistente. Selezionare un'altra forma e incollarla.

      Viene creata una copia della prima forma. Ha un nuovo nome ed è collegato alla seconda forma con un connettore.

Si notino i punti seguenti di questa procedura:

  • Creando direttive di merge degli elementi, è possibile consentire a qualsiasi classe di elemento di accettare qualsiasi altro elemento. L'EMD viene creato nella classe di dominio ricevente e la classe di dominio accettata viene specificata nel campo Classe Index.

  • Definendo i percorsi, è possibile specificare i collegamenti da usare per connettere il nuovo elemento al modello esistente.

    I collegamenti specificati devono includere una relazione di incorporamento.

  • L'EMD influisce sia sulla creazione dalla casella degli strumenti che sulle operazioni incollate.

    Se si scrive codice personalizzato che crea nuovi elementi, è possibile richiamare in modo esplicito l'EMD usando il ElementOperations.Merge metodo . In questo modo, il codice collega nuovi elementi al modello nello stesso modo delle altre operazioni. Per altre informazioni, vedere Personalizzazione del comportamento di copia.

Esempio: Aggiunta di codice Accept personalizzato a un EMD

Aggiungendo codice personalizzato a un EMD, è possibile definire un comportamento di unione più complesso. Questo semplice esempio impedisce all'utente di aggiungere più di un numero fisso di elementi al diagramma. Nell'esempio viene modificato l'EMD predefinito che accompagna una relazione di incorporamento.

Per scrivere codice Di accettazione personalizzato per limitare l'aggiunta dell'utente

  1. Creare un linguaggio DSL usando il modello di soluzione Linguaggio minimo. Aprire il diagramma delle definizioni DSL.

  2. In Esplora DSL espandere Classi di dominio, ExampleModel, Direttive di merge degli elementi. Selezionare la direttiva merge dell'elemento denominata ExampleElement.

    Questo EMD controlla come l'utente può creare nuovi ExampleElement oggetti nel modello, ad esempio trascinando dalla casella degli strumenti.

  3. Nella finestra Dettagli DSL selezionare Usa accettazione personalizzata.

  4. Ricompila la soluzione. Questa operazione richiederà più tempo del solito perché il codice generato verrà aggiornato dal modello.

    Verrà segnalato un errore di compilazione simile al seguente: "Company.ElementMergeSample.ExampleElement non contiene una definizione per CanMergeExampleElement..."

    È necessario implementare il metodo CanMergeExampleElement.

  5. Creare un nuovo file di codice nel progetto Dsl . Sostituire il relativo contenuto con il codice seguente e modificare lo spazio dei nomi nello spazio dei nomi del progetto.

    using Microsoft.VisualStudio.Modeling;
    
    namespace Company.ElementMergeSample // EDIT.
    {
      partial class ExampleModel
      {
        /// <summary>
        /// Called whenever an ExampleElement is to be merged into this ExampleModel.
        /// This happens when the user pastes an ExampleElement
        /// or drags from the toolbox.
        /// Determines whether the merge is allowed.
        /// </summary>
        /// <param name="rootElement">The root element in the merging EGP.</param>
        /// <param name="elementGroupPrototype">The EGP that the user wants to merge.</param>
        /// <returns>True if the merge is allowed</returns>
        private bool CanMergeExampleElement(ProtoElementBase rootElement, ElementGroupPrototype elementGroupPrototype)
        {
          // Allow no more than 4 elements to be added:
          return this.Elements.Count < 4;
        }
      }
    }
    

    Questo semplice esempio limita il numero di elementi che possono essere uniti nel modello padre. Per condizioni più interessanti, il metodo può esaminare qualsiasi proprietà e collegamenti dell'oggetto ricevente. Può anche esaminare le proprietà degli elementi di unione, che vengono trasportati in un oggetto ElementGroupPrototype. Per altre informazioni su ElementGroupPrototypes, vedere Personalizzazione del comportamento di copia. Per altre informazioni su come scrivere codice che legge un modello, vedere Esplorazione e aggiornamento di un modello nel codice programma.

  6. Testare il linguaggio DSL:

    1. Premere F5 per ricompilare la soluzione. Quando si apre l'istanza sperimentale di Visual Studio, aprire un'istanza del linguaggio DSL.

    2. Creare nuovi elementi in diversi modi:

      • Trascinare dallo strumento Elemento di esempio nel diagramma.

      • In Esplora modelli di esempio fare clic con il pulsante destro del mouse sul nodo radice e quindi scegliere Aggiungi nuovo elemento di esempio.

      • Copiare e incollare un elemento nel diagramma.

    3. Verificare che non sia possibile usare uno di questi modi per aggiungere più di quattro elementi al modello. Questo perché tutti usano la direttiva element merge.

Esempio: Aggiunta di codice unione personalizzato a un EMD

Nel codice di unione personalizzato è possibile definire cosa accade quando l'utente trascina uno strumento o incolla in un elemento. Esistono due modi per definire un'unione personalizzata:

  1. Imposta Usa unione personalizzata e specificare il codice richiesto. Il codice sostituisce il codice di merge generato. Utilizzare questa opzione se si desidera ridefinire completamente le operazioni di merge.

  2. Eseguire l'override del MergeRelate metodo e facoltativamente il MergeDisconnect metodo . A tale scopo, è necessario impostare la proprietà Generate Double Derived della classe di dominio. Il codice può chiamare il codice di merge generato nella classe di base. Utilizzare questa opzione se si desidera eseguire operazioni aggiuntive dopo l'esecuzione dell'unione.

    Questi approcci influiscono solo sulle unioni eseguite usando questo EMD. Se si desidera influire su tutti i modi in cui è possibile creare l'elemento unito, un'alternativa consiste nel definire un oggetto AddRule nella relazione di incorporamento e un DeleteRule oggetto nella classe di dominio unita. Per altre informazioni, vedere Regole propagate modifiche all'interno del modello.

Per eseguire l'override di MergeRelate

  1. Nella definizione DSL assicurarsi di aver definito l'EMD a cui si vuole aggiungere codice. Se si vuole, è possibile aggiungere percorsi e definire codice di accettazione personalizzato come descritto nelle sezioni precedenti.

  2. Nel diagramma DslDefinition selezionare la classe ricevente dell'unione. In genere è la classe alla fine di una relazione di incorporamento.

    Ad esempio, in un linguaggio DSL generato dalla soluzione Linguaggio minimo selezionare ExampleModel.

  3. Nella finestra Proprietà impostare Genera doppio derivato su true.

  4. Ricompila la soluzione.

  5. Esaminare il contenuto di Dsl\Generated Files\DomainClasses.cs. Cercare i metodi denominati MergeRelate ed esaminarne il contenuto. In questo modo sarà possibile scrivere versioni personalizzate.

  6. In un nuovo file di codice scrivere una classe parziale per la classe ricevente ed eseguire l'override del MergeRelate metodo . Ricordarsi di chiamare il metodo di base. Ad esempio:

    partial class ExampleModel
    {
      /// <summary>
      /// Called when the user drags or pastes an ExampleElement onto the diagram.
      /// Sets the time of day as the name.
      /// </summary>
      /// <param name="sourceElement">Element to be added</param>
      /// <param name="elementGroup">Elements to be merged</param>
      protected override void MergeRelate(ModelElement sourceElement, ElementGroup elementGroup)
      {
        // Connect the element according to the EMD:
        base.MergeRelate(sourceElement, elementGroup);
    
        // Custom actions:
        ExampleElement mergingElement = sourceElement as ExampleElement;
        if (mergingElement != null)
        {
          mergingElement.Name = DateTime.Now.ToLongTimeString();
        }
      }
    }
    

Per scrivere codice di merge personalizzato

  1. In Dsl\Generated Code\DomainClasses.cs esaminare i metodi denominati MergeRelate. Questi metodi creano collegamenti tra un nuovo elemento e il modello esistente.

    Esaminare anche i metodi denominati MergeDisconnect. Questi metodi scollegano un elemento dal modello quando deve essere eliminato.

  2. In Esplora DSL selezionare o creare la direttiva element merge da personalizzare. Nella finestra Dettagli DSL impostare Usa unione personalizzata.

    Quando si imposta questa opzione, le opzioni Elaborazione unione e Merge in avanti vengono ignorate. Il codice viene invece usato.

  3. Ricompila la soluzione. L'aggiornamento dei file di codice generati dal modello richiederà più tempo del solito.

    Verranno visualizzati messaggi di errore. Fare doppio clic sui messaggi di errore per visualizzare le istruzioni nel codice generato. Queste istruzioni richiedono di fornire due metodi, MergeRelateYourDomainClass e MergeDisconnectYourDomainClass

  4. Scrivere i metodi in una definizione di classe parziale in un file di codice separato. Gli esempi esaminati in precedenza dovrebbero suggerire gli elementi necessari.

    Il codice di merge personalizzato non influirà sul codice che crea direttamente oggetti e relazioni e non influirà su altri EMD. Per assicurarsi che le modifiche aggiuntive vengano implementate indipendentemente dal modo in cui viene creato l'elemento, prendere in considerazione la scrittura di e AddRule un DeleteRule oggetto . Per altre informazioni, vedere Regole propagate modifiche all'interno del modello.

Reindirizzamento di un'operazione di merge

Una direttiva merge forward reindirizza la destinazione di un'operazione di merge. In genere, la nuova destinazione è l'elemento padre di incorporamento della destinazione iniziale.

Ad esempio, in un linguaggio DSL creato con il modello di diagramma dei componenti, le porte sono incorporate in Componenti. Le porte vengono visualizzate come forme piccole sul bordo di una forma componente. L'utente crea le porte trascinando lo strumento Porta in una forma Componente. In alcuni casi, tuttavia, l'utente trascina erroneamente lo strumento Porta su una porta esistente, anziché sul componente e l'operazione non riesce. Si tratta di un errore semplice quando sono presenti diverse porte esistenti. Per consentire all'utente di evitare questo problema, è possibile consentire il trascinamento delle porte in una porta esistente, ma l'azione viene reindirizzata al componente padre. L'operazione funziona come se l'elemento di destinazione fosse il componente.

È possibile creare una direttiva merge forward nella soluzione Modello componente. Se si compila ed esegue la soluzione originale, si noterà che gli utenti possono trascinare un numero qualsiasi di elementi Porta di input o Porta di output dalla casella degli strumenti a un elemento Component. Tuttavia, non possono trascinare una porta in una porta esistente. Il puntatore Non disponibile avvisa che lo spostamento non è abilitato. Tuttavia, è possibile creare una direttiva di tipo merge forward in modo che una porta eliminata involontariamente su una porta di input esistente venga inoltrata all'elemento Component.

Per creare una direttiva di tipo merge forward

  1. Creare una soluzione Strumenti di linguaggio specifici del dominio usando il modello modello di componente.

  2. Visualizzare Dsl Explorer aprendo DslDefinition.dsl.

  3. In Esplora DSL espandere Classi di dominio.

  4. La classe di dominio astratto ComponentPort è la classe base di InPort e OutPort. Fare clic con il pulsante destro del mouse su ComponentPort e quindi scegliere Aggiungi nuova direttiva unione elemento.

    Viene visualizzato un nuovo nodo Element Merge Directive (Direttiva merge elementi) sotto il nodo Element Merge Directive (Direttive di merge degli elementi).

  5. Selezionare il nodo Element Merge Directive (Direttiva merge elementi) e aprire la finestra Dettagli DSL.

  6. Nell'elenco Classe di indicizzazione selezionare ComponentPort.

  7. Selezionare Inoltra unione a una classe di dominio diversa.

  8. Nell'elenco di selezione percorso espandere ComponentPort, espandere ComponentHasPortse quindi selezionare Componente.

    Il nuovo percorso dovrebbe essere simile al seguente:

    ComponentHasPorts.Component/! Componente

  9. Salvare la soluzione e quindi trasformare i modelli facendo clic sul pulsante all'estrema destra sulla barra degli strumenti Esplora soluzioni.

  10. Compilare ed eseguire la soluzione. Viene visualizzata una nuova istanza di Visual Studio.

  11. In Esplora soluzioni aprire Sample.mydsl. Viene visualizzato il diagramma e la casella degli strumenti ComponentLanguage.

  12. Trascinare una porta di input dalla casella degli strumenti a un'altra porta di input. Trascinare quindi un OutputPort in un InputPort e quindi in un altro OutputPort.

    Il puntatore Non disponibile non dovrebbe essere visualizzato e dovrebbe essere possibile eliminare la nuova porta di input su quella esistente. Selezionare la nuova porta di input e trascinarla in un altro punto del componente.