Acceder a la selección actual y restringirla

Al escribir un comando o un controlador de gestos para el idioma específico del dominio, puede determinar en qué elemento ha hecho clic el usuario con el botón derecho. También puede evitar que se seleccionen algunas formas o campos. Por ejemplo, puede establecer que cuando el usuario hace clic en un decorador de iconos, en su lugar se seleccione la forma que lo contiene. Restringir la selección de esta manera reduce el número de controladores que tiene que escribir. También lo facilita al usuario, que puede hacer clic en cualquier parte de la forma sin tener que evitar el decorador.

Obtener acceso a la selección actual desde un controlador de comandos

La clase de conjunto de comandos para un lenguaje específico del dominio contiene los controladores de comandos de los comandos personalizados. La clase CommandSet, de la que deriva la clase de conjunto de comandos para un lenguaje específico del dominio, proporciona algunos miembros para acceder a la selección actual.

Según el comando, es posible que el controlador de comandos necesite la selección en el diseñador de modelos, el explorador de modelos o la ventana activa.

Acceso a la información de selección

  1. La clase CommandSet define los siguientes miembros que se pueden usar para tener acceso a la selección actual.

    Miembro Descripción
    Método IsAnyDocumentSelectionCompartment Devuelve true si alguno de los elementos seleccionados en el diseñador de modelos es una forma de compartimiento, de lo contrario, false.
    Método IsDiagramSelected Devuelve true si el diagrama está seleccionado en el diseñador de modelos, de lo contrario, false.
    Método IsSingleDocumentSelection Devuelve true si se selecciona exactamente un elemento en el diseñador de modelos, de lo contrario, false.
    Método IsSingleSelection Devuelve true si se selecciona exactamente un elemento en la ventana activa, de lo contrario, false.
    Propiedad CurrentDocumentSelection Obtiene una colección de solo lectura de los elementos seleccionados en el diseñador de modelos.
    Propiedad CurrentSelection Obtiene una colección de solo lectura de los elementos seleccionados en la ventana activa.
    Propiedad SingleDocumentSelection Obtiene el elemento principal de la selección en el diseñador de modelos.
    Propiedad SingleSelection Obtiene el elemento principal de la selección en la ventana activa.
  2. La propiedad CurrentDocView de la clase CommandSet proporciona acceso al objeto DiagramDocView que representa la ventana del diseñador de modelos y proporciona acceso adicional a los elementos seleccionados en el diseñador de modelos.

  3. Además, el código generado define una propiedad de ventana de herramientas del explorador y una propiedad de selección del explorador en la clase del conjunto de comandos para el idioma específico del dominio.

    • La propiedad de la ventana de herramientas del explorador devuelve una instancia de la clase de ventana de herramientas del explorador para el idioma específico del dominio. La clase de ventana de herramientas del explorador se deriva de la clase ModelExplorerToolWindow y representa el explorador de modelos para el lenguaje específico del dominio.

    • La propiedad ExplorerSelection devuelve el elemento seleccionado en la ventana del explorador de modelos para el idioma específico del dominio.

Determinación de la ventana activa

La interfaz IMonitorSelectionService contiene miembros que proporcionan acceso al estado de selección actual en el shell. Puede obtener un objeto IMonitorSelectionService de la clase de paquete o la clase de conjunto de comandos para el idioma específico del dominio a través de la propiedad MonitorSelection definida en la clase base de cada uno. La clase de paquete se deriva de la clase ModelingPackage y la clase de conjunto de comandos se deriva de la clase CommandSet.

Determinación del tipo de ventana activa desde un controlador de comandos

  1. La propiedad MonitorSelection de la clase CommandSet devuelve un objeto IMonitorSelectionService que proporciona acceso al estado de selección actual en el shell.

  2. La propiedad CurrentSelectionContainer de la interfaz IMonitorSelectionService obtiene el contenedor de selección activo, que puede ser diferente de la ventana activa.

  3. Agregue las propiedades siguientes a la clase de conjunto de comandos para el idioma específico del dominio para determinar qué tipo de ventana está activo.

    // using Microsoft.VisualStudio.Modeling.Shell;
    
    // Returns true if the model designer is the active selection container;
    // otherwise, false.
    protected bool IsDesignerActive
    {
        get
        {
            return (this.MonitorSelection.CurrentSelectionContainer
                is DiagramDocView);
        }
    }
    
    // Returns true if the model explorer is the active selection container;
    // otherwise, false.
    protected bool IsExplorerActive
    {
        get
        {
            return (this.MonitorSelection.CurrentSelectionContainer
                is ModelExplorerToolWindow);
        }
    }
    

Restricción de la selección

Si agrega reglas de selección puede controlar qué elementos se seleccionan cuando el usuario selecciona un elemento en el modelo. Por ejemplo, para permitir que el usuario trate varios elementos como una sola unidad, puede usar una regla de selección.

Creación de una regla de selección

  1. Creación de un archivo de código personalizado en el proyecto DSL

  2. Defina una clase de regla de selección derivada de la clase DiagramSelectionRules.

  3. Invalide el método GetCompliantSelection de la clase de regla de selección para aplicar los criterios de selección.

  4. Agregue una definición de clase parcial para la clase ClassDiagram al archivo de código personalizado.

    La clase ClassDiagram se deriva de la clase Diagram y se define en el archivo de código generado, Diagram.cs, en el proyecto DSL.

  5. Invalide la propiedad SelectionRules de la clase ClassDiagram para devolver la regla de selección personalizada.

    La implementación predeterminada de la propiedad SelectionRules obtiene un objeto de regla de selección que no modifica la selección.

Ejemplo

El archivo de código siguiente crea una regla de selección que expande la selección para incluir todas las instancias de cada una de las formas de dominio que se seleccionaron inicialmente.

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

namespace CompanyName.ProductName.GroupingDsl
{
    public class CustomSelectionRules : DiagramSelectionRules
    {
        protected Diagram diagram;
        protected IElementDirectory elementDirectory;

        public CustomSelectionRules(Diagram diagram)
        {
            if (diagram == null) throw new ArgumentNullException();

            this.diagram = diagram;
            this.elementDirectory = diagram.Store.ElementDirectory;
        }

        /// <summary>Called by the design surface to allow selection filtering.
        /// </summary>
        /// <param name="currentSelection">[in] The current selection before any
        /// ShapeElements are added or removed.</param>
        /// <param name="proposedItemsToAdd">[in/out] The proposed DiagramItems to
        /// be added to the selection.</param>
        /// <param name="proposedItemsToRemove">[in/out] The proposed DiagramItems
        /// to be removed from the selection.</param>
        /// <param name="primaryItem">[in/out] The proposed DiagramItem to become
        /// the primary DiagramItem of the selection. A null value signifies that
        /// the last DiagramItem in the resultant selection should be assumed as
        /// the primary DiagramItem.</param>
        /// <returns>true if some or all of the selection was accepted; false if
        /// the entire selection proposal was rejected. If false, appropriate
        /// feedback will be given to the user to indicate that the selection was
        /// rejected.</returns>
        public override bool GetCompliantSelection(
            SelectedShapesCollection currentSelection,
            DiagramItemCollection proposedItemsToAdd,
            DiagramItemCollection proposedItemsToRemove,
            DiagramItem primaryItem)
        {
            if (currentSelection.Count == 0 && proposedItemsToAdd.Count == 0) return true;

            HashSet<DomainClassInfo> itemsToAdd = new HashSet<DomainClassInfo>();

            foreach (DiagramItem item in proposedItemsToAdd)
            {
                if (item.Shape != null)
                    itemsToAdd.Add(item.Shape.GetDomainClass());
            }
            proposedItemsToAdd.Clear();
            foreach (DomainClassInfo classInfo in itemsToAdd)
            {
                foreach (ModelElement element
                    in this.elementDirectory.FindElements(classInfo, false))
                {
                    if (element is ShapeElement)
                    {
                        proposedItemsToAdd.Add(
                            new DiagramItem((ShapeElement)element));
                    }
                }
            }

            return true;
        }
    }

    public partial class ClassDiagram
    {
        protected CustomSelectionRules customSelectionRules = null;

        protected bool multipleSelectionMode = true;

        public override DiagramSelectionRules SelectionRules
        {
            get
            {
                if (multipleSelectionMode)
                {
                    if (customSelectionRules == null)
                    {
                        customSelectionRules = new CustomSelectionRules(this);
                    }
                    return customSelectionRules;
                }
                else
                {
                    return base.SelectionRules;
                }
            }
        }
    }
}