Personalizar la creación y el movimiento de los elementos

Puede permitir que un elemento se arrastre a otro, ya sea desde el cuadro de herramientas o en una operación de pegado o movimiento. Puede tener los elementos movidos vinculados a los elementos de destino mediante las relaciones que especifique.

Una directiva de fusión de elementos mediante combinación (EMD) especifica lo que sucede cuando un elemento de modelo se fusiona mediante combinación en otro elemento de modelo. Esto ocurre cuando:

  • El usuario arrastra desde el cuadro de herramientas al diagrama o una forma.

  • El usuario crea un elemento mediante un menú Agregar en el explorador o una forma de compartimiento.

  • El usuario mueve un elemento de una calle a otra.

  • El usuario pega un elemento.

  • El código de programa llama a la directiva de fusión de elementos mediante combinación.

Aunque las operaciones de creación pueden parecer distintas de las operaciones de copia, realmente funcionan de la misma manera. Cuando se agrega un elemento desde el cuadro de herramientas, por ejemplo, se replica un prototipo de este. El prototipo se fusiona mediante combinación con el modelo de la misma manera que los elementos que se han copiado de otra parte del modelo.

La responsabilidad de una EMD es decidir cómo se debe fusionar mediante combinación un objeto o grupo de objetos con una ubicación determinada del modelo. En concreto, decide de qué relaciones se debe crear una instancia para vincular el grupo fusionado mediante combinación al modelo. También puede personalizarlo para establecer propiedades y crear objetos adicionales.

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.

Una EMD se genera automáticamente al definir una relación de inclusión. Esta EMD predeterminada crea una instancia de la relación cuando los usuarios agregan nuevas instancias secundarias al elemento primario. Puede modificar estas EMD predeterminadas agregando código personalizado, por ejemplo.

También puede agregar sus propias EMD en la definición de DSL para permitir que los usuarios arrastren o peguen diferentes combinaciones de clases fusionadas mediante combinación y receptoras.

Definición de una directiva de fusión de elementos mediante combinación

Puede agregar directivas de fusión de elementos mediante combinación a clases de dominio, relaciones de dominio, formas, conectores y diagramas. Puede agregarlas o encontrarlas en el Explorador de DSL en la clase de dominio receptora. La clase receptora es la clase de dominio del elemento que ya está en el modelo y con el que se fusionará mediante combinación el elemento nuevo o copiado.

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 clase de indexación es la clase de dominio de los elementos que se pueden fusionar mediante combinación con los miembros de la clase receptora. Esta EMD también fusionará mediante combinación las instancias de subclases de la clase de indexación, a menos que establezca Aplicable a las subclases en False.

Hay dos tipos de directiva de fusión mediante combinación:

  • Una directiva de fusión de proceso mediante combinación especifica las relaciones por las que se debe vincular el nuevo elemento al árbol.

  • Una directiva de reenvío de fusión mediante combinación redirige el nuevo elemento a otro elemento receptor, normalmente un elemento primario.

Puede agregar código personalizado a las directivas de fusión mediante combinación:

  • Establezca Usa aceptación personalizada para agregar su propio código a fin de determinar si se debe fusionar mediante combinación una instancia determinada del elemento de indexación con el elemento de destino. Cuando el usuario arrastra desde el cuadro de herramientas, el puntero "no válido" muestra si el código no permite la fusión mediante combinación.

    Por ejemplo, podría permitir la fusión mediante combinación solo cuando el elemento receptor esté en un estado determinado.

  • EstablezcaUsa fusión personalizada para agregar/proporcionar su propio código a fin de definir los cambios realizados en el modelo al llevarse a cabo la fusión mediante combinación.

    Por ejemplo, podría establecer propiedades en el elemento fusionado mediante combinación utilizando los datos de su nueva ubicación en el modelo.

Nota

Si escribe código de fusión mediante combinación personalizado, solo afecta a las fusiones mediante combinación que se realizan utilizando esta EMD. Si hay otras EMD que fusionan mediante combinación el mismo tipo de objeto o si hay otro código personalizado que crea estos objetos sin usar la EMD, no se verán afectados por el código de fusión mediante combinación personalizado.

Si desea asegurarse de que el código personalizado procese siempre un nuevo elemento o una nueva relación, considere la posibilidad de definir una regla de tipo AddRule en la relación de inclusión y una regla de tipo DeleteRule en la clase de dominio del elemento. Para obtener más información, consulte Las reglas propagan los cambios dentro del modelo.

Ejemplo: definir una EMD sin código personalizado

En el ejemplo siguiente se permite a los usuarios crear un elemento y un conector al mismo tiempo arrastrando desde el cuadro de herramientas a una forma existente. En el ejemplo se agrega una EMD a la definición de DSL. Antes de esta modificación, los usuarios pueden arrastrar herramientas al diagrama, pero no a las formas existentes.

Los usuarios también pueden pegar elementos en otros elementos.

Para permitir que los usuarios creen un elemento y un conector al mismo tiempo

  1. Cree un nuevo DSL mediante la plantilla de solución Lenguaje mínimo.

    Al ejecutar este DSL, le permite crear formas y conectores entre las formas. No puede arrastrar una nueva forma ExampleElement desde el cuadro de herramientas a una forma existente.

  2. Para permitir que los usuarios fusionen mediante combinación elementos con formas ExampleElement, cree una nueva EMD en la clase de dominio ExampleElement:

    1. En el Explorador de DSL, expanda Clases de dominio. Haga clic con el botón derecho en ExampleElement y, a continuación, haga clic en Agregar nueva directiva de fusión de elementos mediante combinación.

    2. Asegúrese de que la ventana Detalles de DSL está abierta para que pueda ver los detalles de la nueva EMD (Menú: Ver, Otras ventanas, Detalles de DSL).

  3. Establezca la clase de indexación en la ventana Detalles de DSL para definir qué clase de elementos se pueden fusionar mediante combinación con objetos ExampleElement.

    En este ejemplo, seleccione ExampleElements, para que el usuario pueda arrastrar nuevos elementos a los elementos existentes.

    Tenga en cuenta que la clase de indexación se convierte en el nombre de la EMD en el Explorador de DSL.

  4. En Fusionar proceso mediante combinación con creación de vínculos, agregue dos rutas de acceso:

    • Una ruta de acceso vincula el nuevo elemento al modelo primario. La expresión de ruta de acceso que debe escribir navega desde el elemento existente hasta la relación de inclusión con el modelo primario. Por último, especifica el rol en el nuevo vínculo al que se asignará el nuevo elemento. La ruta de acceso es la siguiente:

      ExampleModelHasElements.ExampleModel/!ExampleModel/.Elements

    • La otra ruta de acceso vincula el nuevo elemento al ya existente. La expresión de ruta de acceso especifica la relación de referencia y el rol al que se asignará el nuevo elemento. Esta ruta de acceso es la siguiente:

      ExampleElementReferencesTargets.Sources

      Puede usar la herramienta de navegación de la ruta para crear cada ruta de acceso:

      1. En Fusionar proceso mediante combinación con creación de vínculos en rutas, haga clic en <agregar ruta de acceso>.

      2. Haga clic en la flecha desplegable situada a la derecha del elemento de lista. Aparecerá una vista de árbol.

      3. Expanda los nodos del árbol para formar la ruta de acceso que desea especificar.

  5. Pruebe el DSL:

    1. Presione F5 para recompilar y ejecutar la solución.

      La recompilación tardará más de lo habitual porque el código generado se actualizará a partir de plantillas de texto a fin de ajustarlo a la nueva definición de DSL.

    2. Cuando se haya iniciado la instancia experimental de Visual Studio, abra un archivo de modelo de su DSL. Cree algunos elementos de ejemplo.

    3. Arrastre desde la herramienta Elemento de ejemplo a una forma existente.

      Aparecerá una nueva forma, vinculada a la forma existente con un conector.

    4. Copie una forma existente. Seleccione otra forma y haga clic en Pegar.

      Se creará una copia de la primera forma. Tiene un nuevo nombre, vinculado a la segunda forma con un conector.

Tenga en cuenta los puntos siguientes de este procedimiento:

  • Puede permitir que cualquier clase de elemento acepte cualquier otra creando directivas de fusión de elementos mediante combinación. La EMD se crea en la clase de dominio receptora y la clase de dominio aceptada se especifica en el campo Clase de índice.

  • Al definir rutas de acceso, puede especificar los vínculos que se deben usar para conectar el nuevo elemento al modelo existente.

    Los vínculos que especifique deben incluir una relación de inclusión.

  • La EMD afecta tanto a la creación a partir del cuadro de herramientas como también a las operaciones de pegado.

    Si escribe código personalizado que crea nuevos elementos, puede invocar explícitamente la EMD mediante el método ElementOperations.Merge. Esto garantiza que el código vincule nuevos elementos al modelo de la misma manera que otras operaciones. Para obtener más información, consulte Personalizar comportamiento de copia.

Ejemplo: agregar código de aceptación personalizada a una EMD

Al agregar código personalizado a una EMD, puede definir un comportamiento de fusión mediante combinación más complejo. En este sencillo ejemplo se impide que el usuario agregue más de un número fijo de elementos al diagrama. En el ejemplo se modifica la EMD predeterminada que acompaña a una relación de inclusión.

Para escribir código de aceptación personalizada a fin de restringir lo que puede agregar el usuario

  1. Cree un DSL mediante la plantilla de solución Lenguaje mínimo. Abra el diagrama de definición de DSL.

  2. En el Explorador de DSL, expanda Clases de dominio, ExampleModel, Directivas de fusión de elementos mediante combinación. Seleccione la directiva de fusión de elementos mediante combinación denominada ExampleElement.

    Esta EMD controla cómo puede crear el usuario objetos ExampleElement nuevos en el modelo, por ejemplo arrastrando desde el cuadro de herramientas.

  3. En la ventana Detalles de DSL, seleccione Usa aceptación personalizada.

  4. Recompilar la solución. Esto tardará más de lo habitual porque el código generado se actualizará desde el modelo.

    Se notificará un error de compilación similar a: "Company.ElementMergeSample.ExampleElement no contiene una definición para CanMergeExampleElement..."

    Debe implementar el método CanMergeExampleElement.

  5. Cree un nuevo archivo de código en el proyecto Dsl. Reemplace su contenido por el código siguiente y cambie el espacio de nombres al espacio de nombres del proyecto.

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

    En este sencillo ejemplo se restringe el número de elementos que se pueden fusionar mediante combinación en el modelo primario. Para obtener condiciones más interesantes, el método puede inspeccionar cualquiera de las propiedades y vínculos del objeto receptor. También puede inspeccionar las propiedades de los elementos de fusión mediante combinación, que se realizan en un ElementGroupPrototype. Para obtener más información sobre ElementGroupPrototypes, consulte Personalizar comportamiento de copia. Para obtener más información sobre cómo escribir código que lea un modelo, consulte Navegar por un modelo en el código de programa y actualizarlo.

  6. Pruebe el DSL:

    1. Presione F5 para recompilar la solución. Cuando se abra la instancia experimental de Visual Studio, abra una instancia de su DSL.

    2. Cree nuevos elementos de varias maneras:

      • Arrastre desde la herramienta Elemento de ejemplo al diagrama.

      • En el Explorador de modelos de ejemplo, haga clic con el botón derecho en el nodo raíz y, a continuación, haga clic en Agregar nuevo elemento de ejemplo.

      • Copie y pegue un elemento en el diagrama.

    3. Compruebe que no puede usar ninguna de estas formas de agregar más de cuatro elementos al modelo. Esto se debe a que todos usan la directiva de fusión de elementos mediante combinación.

Ejemplo: agregar código de fusión mediante combinación personalizado a una EMD

En el código de fusión mediante combinación personalizado, puede definir lo que sucede cuando el usuario arrastra una herramienta o la pega a un elemento. Hay dos maneras de definir una fusión mediante combinación personalizada:

  1. Establezca Usa fusión personalizada y proporcione el código necesario. El código reemplaza el código de fusión mediante combinación generado. Use esta opción si desea volver a definir completamente lo que hace la fusión mediante combinación.

  2. Invalide el método MergeRelate y, opcionalmente, el método MergeDisconnect. Para ello, debe establecer la propiedad Genera doble derivada de la clase de dominio. El código puede llamar al código de fusión mediante combinación generado en la clase base. Use esta opción si desea realizar operaciones adicionales una vez que se haya llevado a cabo la fusión mediante combinación.

    Estos enfoques solo afectan a las fusiones mediante combinación que se realizan utilizando esta EMD. Si desea que se vean afectadas todas las formas en que se puede crear el elemento fusionado mediante combinación, una alternativa consiste en definir una regla de tipo AddRule en la relación de inclusión y una regla de tipo DeleteRule en la clase de dominio fusionada mediante combinación. Para obtener más información, consulte Las reglas propagan los cambios dentro del modelo.

Para invalidar MergeRelate

  1. En la definición de DSL, asegúrese de que ha definido la EMD a la que desea agregar código. Si lo desea, puede agregar rutas de acceso y definir código de aceptación personalizada como se describe en las secciones anteriores.

  2. En el diagrama DslDefinition, seleccione la clase receptora de la fusión mediante combinación. Normalmente, es la clase del extremo de origen de una relación de inclusión.

    Por ejemplo, en un DSL generado a partir de la solución Lenguaje mínimo, seleccione ExampleModel.

  3. En la ventana Propiedades, establezca Genera doble derivada en true.

  4. Recompilar la solución.

  5. Inspeccione el contenido de Dsl\Generated Files\DomainClasses.cs. Busque métodos denominados MergeRelate y examine su contenido. Esto le ayudará a escribir sus propias versiones.

  6. En un nuevo archivo de código, escriba una clase parcial para la clase receptora e invalide el método MergeRelate. Recuerde llamar al método base. Por ejemplo:

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

Para escribir código de fusión mediante combinación personalizado

  1. En Dsl\Generated Code\DomainClasses.cs, inspeccione los métodos denominados MergeRelate. Estos métodos crean vínculos entre un nuevo elemento y el modelo existente.

    Además, inspeccione los métodos denominados MergeDisconnect. Estos métodos desvinculan un elemento del modelo cuando se va a eliminar.

  2. En el Explorador de DSL, seleccione o cree la directiva de fusión de elementos mediante combinación que desea personalizar. En la ventana Detalles de DSL, establezca Usa fusión personalizada.

    Al establecer esta opción, se omiten las opciones de fusión de proceso y reenvío de fusión mediante combinación. En su lugar, se usará su código.

  3. Recompilar la solución. Tardará más de lo habitual porque los archivos de código generado se actualizarán desde el modelo.

    Aparecerán mensajes de error. Haga doble clic en los mensajes de error para ver las instrucciones en el código generado. Estas instrucciones le piden que proporcione dos métodos, MergeRelateYourDomainClass y MergeDisconnectYourDomainClass.

  4. Escriba los métodos en una definición de clase parcial en un archivo de código independiente. En los ejemplos que inspeccionó anteriormente debe sugerirse lo que necesita.

    El código de fusión mediante combinación personalizado no afectará al código que crea objetos y relaciones directamente ni a otras EMD. Para asegurarse de que los cambios adicionales se implementan independientemente de cómo se cree el elemento, considere la posibilidad de escribir una regla de tipo AddRule y otra de tipo DeleteRule en su lugar. Para obtener más información, consulte Las reglas propagan los cambios dentro del modelo.

Redireccionamiento de una operación de fusión mediante combinación

Una directiva de reenvío de fusión mediante combinación redirige el destino de una operación de fusión mediante combinación. Normalmente, el nuevo destino es el elemento primario de inclusión del destino inicial.

Por ejemplo, en un DSL que se creó con la plantilla Diagrama de componentes, los puertos se insertan en componentes. Los puertos se muestran como pequeñas formas en el borde de una forma de componente. El usuario crea puertos arrastrando la herramienta de puerto a una forma de componente. En ocasiones, sin embargo, el usuario arrastra erróneamente la herramienta de puerto a un puerto existente, en lugar del componente, y se produce un error en la operación. Este error se produce fácilmente cuando hay varios puertos existentes. Para ayudar al usuario a evitar esta molestia, puede permitir que los puertos se arrastren a un puerto existente y, sin embargo, tener la acción redirigida al componente primario. La operación funciona como si el elemento de destino fuera el componente.

Puede crear una directiva de reenvío de fusión mediante combinación en la solución de modelo de componentes. Si compila y ejecuta la solución original, debería ver que los usuarios pueden arrastrar cualquier número de elementos Puerto de entrada o Puerto de salida desde el cuadro de herramientas a un elemento de componente. Sin embargo, no pueden arrastrar un puerto a uno ya existente. El puntero no disponible les alerta de que este movimiento no está habilitado. Sin embargo, puede crear una directiva de reenvío de fusión mediante combinación para que un puerto que se coloque involuntariamente en un puerto de entrada existente se reenvíe al elemento de componente.

Para crear una directiva de reenvío de fusión mediante combinación

  1. Cree una solución de Herramientas del lenguaje específico de dominio mediante la plantilla Modelo de componentes.

  2. Para mostrar el Explorador de DSL, abra DslDefinition.dsl.

  3. En el Explorador de DSL, expanda Clases de dominio.

  4. La clase de dominio abstracta ComponentPort es la clase base tanto de InPort como de OutPort. Haga clic con el botón derecho en ComponentPort y, a continuación, haga clic en Agregar nueva directiva de fusión de elementos mediante combinación.

    Aparecerá un nuevo nodo Directiva de fusión de elementos mediante combinación bajo el nodo Directivas de fusión de elementos mediante combinación.

  5. Seleccione el nodo Directiva de fusión de elementos mediante combinación y abra la ventana Detalles de DSL.

  6. En la lista de clases de indexación, seleccione ComponentPort.

  7. Seleccione Reenviar fusión mediante combinación a otra clase de dominio.

  8. En la lista de selección de ruta de acceso, expanda ComponentPort y ComponentHasPorts y, a continuación, seleccione Componente.

    La nueva ruta de acceso debe ser similar a esta:

    ComponentHasPorts.Component/!Component

  9. Guarde la solución y, a continuación, transforme las plantillas haciendo clic en el botón situado más a la derecha en la barra de herramientas del Explorador de soluciones.

  10. Compile y ejecute la solución. Aparecerá una nueva instancia de Visual Studio.

  11. En el Explorador de soluciones, abra Sample.mydsl. Aparecerá el diagrama y el cuadro de herramientas ComponentLanguage.

  12. Arrastre un puerto de entrada desde el cuadro de herramientas a otro puerto de entrada. A continuación, arrastre un puerto de salida a un puerto de entrada y, a continuación, a otro puerto de salida.

    No debería ver el puntero no disponible y debería poder colocar el nuevo puerto de entrada en el existente. Seleccione el nuevo puerto de entrada y arrástrelo a otro punto del componente.