Personalizar comportamiento de copia
En un lenguaje específico (DSL) creado con la vista de Visual Studio y que modela SDK, puede modificar qué ocurre cuando el usuario copiar y pegar elementos.
Comportamiento de la operación estándar de copiar y pegar
Para habilitar copiar, establezca la propiedad de Pegar de la copia de permiso de nodo de Editor en el Explorador de ADSL.
De forma predeterminada, cuando el usuario copia elementos al portapapeles, los elementos siguientes también se copian:
Descendientes incrustados de los elementos seleccionados.(Es decir, los elementos que son destinos de relaciones de incrustación que son originarias en elementos copiados.)
vínculos de la relación entre los elementos copiados.
Esta regla se aplica de forma recursiva a los elementos y vínculos copiados.
Los elementos y los vínculos copiados se serializarán y almacenados en ElementGroupPrototype (EGP), que se coloca en el portapapeles.
Una imagen de los elementos copiados también se coloca en el portapapeles.Esto permite al usuario pegue en otras aplicaciones como word.
El usuario puede pegar elementos copiados sobre un destino que puede aceptar los elementos según la definición ADSL.Por ejemplo, en un DSL generado de la solución de los componentes, el usuario puede pegar puertos sobre los componentes, pero no al diagrama; y puede pegar los componentes al diagrama, pero no sobre otros componentes.
Personalizar el comportamiento de la copia y pegar
Para obtener más información sobre cómo personalizar el modelo utilizando código de programa, vea Navegar y actualizar un modelo en el código del programa.
Habilitar o deshabilitar la copia, cortela, y péguela.
En el Explorador ADSL, establezca la propiedad de Pegar de la copia de permiso de nodo de Editor .Vínculos de copia al mismo destino. Por ejemplo, tener un cuadro de comentarios copiado vinculado al mismo elemento de asunto.
Establezca la propiedad de Propaga la copia del rol a Copia de la propagación de vincular sólo.Para obtener más información, vea Personalizar el comportamiento de la copia del vínculo.elementos vinculados copia. Por ejemplo, al copiar un nuevo elemento, las copias de cualquier cuadro de comentarios vinculado se haga también.
Establezca la propiedad de Propaga la copia del rol a Copia de la propagación de vinculación y encargado de rol opuesto.Para obtener más información, vea Personalizar el comportamiento de la copia del vínculo.elementos rápidamente duplicados copiando y pegando. Normalmente, el elemento que acaba de copiar todavía está seleccionado, y no puede pegar el mismo tipo de elemento sobre él.
Agregue una directiva de la combinación de elementos a la clase de dominio, y establézcala para reenviar combinaciones a la clase primaria.esto tendrá el mismo efecto en operaciones de arrastre.Para obtener más información, vea Personalizar la creación y el movimiento de los elementos.-O bien-
Seleccione el diagrama antes de pegar los elementos, reemplazando ClipboardCommandSet.ProcessOnPasteCommand().agregue este código en un archivo personalizado en el proyecto de DslPackage:
namespace Company.MyDsl { using System.Linq; using Microsoft.VisualStudio.Modeling.Diagrams; using Microsoft.VisualStudio.Modeling.Shell; partial class MyDslClipboardCommandSet { protected override void ProcessOnMenuPasteCommand() { // Deselect the current selection after copying: Diagram diagram = (this.CurrentModelingDocView as SingleDiagramDocView).Diagram; this.CurrentModelingDocView .SelectObjects(1, new object[] { diagram }, 0); } } }
Establezca las relaciones adicionales cuando las gomas del usuario sobre un destino seleccionado. por ejemplo, cuando un cuadro de comentarios se pega sobre un elemento, un vínculo se hace entre ellos.
Agregue una directiva de la combinación de elementos a la clase de dominio de destino, y establézcala para procesar la combinación agregando vínculos.esto tendrá el mismo efecto en operaciones de arrastre.Para obtener más información, vea Personalizar la creación y el movimiento de los elementos.-O bien-
Reemplace ClipboardCommandSet.ProcessOnPasteCommand() para crear vínculos adicionales después de llamar al método base.
Personalizar formatos en los que los elementos se pueden copiar las aplicaciones externas (por ejemplo, para agregar un borde al formulario bitmap.
Reemplazo MyDslClipboardCommandSet.ProcessOnMenuCopyCommand() en el proyecto de DslPackage.Personalizar cómo los elementos se copian en el portapapeles por el comando de copia, pero no en una operación de arrastre.
Reemplazo MyDslClipboardCommandSet.CopyModelElementsIntoElementGroupPrototype() en el proyecto de DslPackage.Diseño de la forma de conservar a través de copia y pegar.
Cuando el usuario copia varias formas, puede conservar sus posiciones relativas cuando se pegan.Esta técnica se muestra en el ejemplo de VMSDK: Ejemplo de esquemas circulares.Para lograr este efecto, agregue las formas y conectores a ElementGroupPrototype copiado.El método más cómodo a reemplazar es ElementOperations.CreateElementGroupPrototype().Para ello, agregue el código siguiente al proyecto de ADSL:
public class MyElementOperations : DesignSurfaceElementOperations { // Create an EGP to add to the clipboard. // Called when the elements to be copied have been // collected into an ElementGroup. protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType) { // Add the shapes and connectors: // Get the elements already in the group: ModelElement[] mels = elementGroup.ModelElements .Concat(elementGroup.ElementLinks) // Omit if the paste target is not the diagram. .ToArray(); // Get their shapes: IEnumerable<PresentationElement> shapes = mels.SelectMany(mel => PresentationViewsSubject.GetPresentation(mel)); elementGroup.AddRange(shapes); return base.CreateElementGroupPrototype (elementGroup, elements, closureType); } public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram) : base(serviceProvider, diagram) { } } // Replace the standard ElementOperations // singleton with your own: partial class MyDslDiagram // EDIT NAME { /// <summary> /// Singleton ElementOperations attached to this diagram. /// </summary> public override DesignSurfaceElementOperations ElementOperations { get { if (singleton == null) { singleton = new MyElementOperations(this.Store as IServiceProvider, this); } return singleton; } } private MyElementOperations singleton = null; }
Pegue las formas en una ubicación especificada, como la posición del cursor actual.
Cuando el usuario copia varias formas, puede conservar sus posiciones relativas cuando se pegan.Esta técnica se muestra en el ejemplo de VMSDK: Ejemplo de esquemas circulares.Para lograr este efecto, reemplace ClipboardCommandSet.ProcessOnMenuPasteCommand() para utilizar la versión ubicación-específica de ElementOperations.Merge().Para ello, agregue el código siguiente en el proyecto de DslPackage:
partial class MyDslClipboardCommandSet // EDIT NAME { /// <summary> /// This method assumes we only want to paste things onto the diagram /// - not onto anything contained in the diagram. /// The base method pastes in a free space on the diagram. /// But if the menu was used to invoke paste, we want to paste in the cursor position. /// </summary> protected override void ProcessOnMenuPasteCommand() { NestedShapesSampleDocView docView = this.CurrentModelingDocView as NestedShapesSampleDocView; // Retrieve data from clipboard: System.Windows.Forms.IDataObject data = System.Windows.Forms.Clipboard.GetDataObject(); Diagram diagram = docView.CurrentDiagram; if (diagram == null) return; if (!docView.IsContextMenuShowing) { // User hit CTRL+V - just use base method. // Deselect anything that's selected, otherwise // pasted item will be incompatible: if (!this.IsDiagramSelected()) { docView.SelectObjects(1, new object[] { diagram }, 0); } // Paste into a convenient spare space on diagram: base.ProcessOnMenuPasteCommand(); } else { // User right-clicked - paste at mouse position. // Utility class: DesignSurfaceElementOperations op = diagram.ElementOperations; ShapeElement pasteTarget = diagram; // Check whether what's in the paste buffer is acceptable on the target. if (pasteTarget != null && op.CanMerge(pasteTarget, data)) { // Although op.Merge would be a no-op if CanMerge failed, we check CanMerge first // so that we don't create an empty transaction (after which Undo would be no-op). using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("paste")) { PointD place = docView.ContextMenuMousePosition; op.Merge(pasteTarget, data, PointD.ToPointF(place)); t.Commit(); } } } } }
Deje los elementos de arrastrar y colocar del usuario.
Vea Cómo: Agregar un controlador para arrastrar y colocar.
Personalizar el comportamiento de la copia del vínculo
Cuando el usuario copia un elemento, el comportamiento estándar es que cualquier elemento incrustado también se copian.Puede modificar el estándar que copia comportamiento.En la definición de DSL, seleccione un rol de un extremo de una relación y en la ventana Propiedades establezca el valor de Propaga la copia .
hay tres valores:
No propaga la copia
Propagar la copia para vincular sólo )a pega el grupo, la nueva copia de este vínculo hará referencia al elemento existente en el otro extremo del vínculo.
Copia de la propagación de vinculación y encargado de rol opuesto - el grupo copiado incluye una copia del elemento en el otro extremo del vínculo.
Los cambios que realice afectarán a los elementos y la imagen se copia que.
Comportamiento programado de copia y pegar
Muchos aspectos del comportamiento de DSL con respecto a la copia, a pegar, a la creación, y la eliminación de objetos rige una instancia de ElementOperations que se acopla al diagrama.Puede modificar el comportamiento ADSL derivando dispone de la clase de ElementOperations y reemplazando la propiedad de ElementOperations de la clase del diagrama.
Sugerencia |
---|
Para obtener más información sobre cómo personalizar el modelo utilizando código de programa, vea Navegar y actualizar un modelo en el código del programa. |
Para definir dispone ElementOperations
En un nuevo archivo del proyecto ADSL, cree una clase que se deriva de DesignSurfaceElementOperations.
Agregue una definición de clase parcial para la clase del diagrama.el nombre de esta clase se puede encontrar en Dsl\GeneratedCode\Diagrams.cs.
En la clase del diagrama, override ElementOperations para devolver una instancia de la subclase de ElementOperations.Debe devolver la misma instancia en cada llamada.
Agregue este código en un archivo de código personalizado en el proyecto de DslPackage:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
public partial class MyDslDiagram
{
public override DesignSurfaceElementOperations ElementOperations
{
get
{
if (this.elementOperations == null)
{
this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
}
return this.elementOperations;
}
}
private MyElementOperations elementOperations = null;
}
public class MyElementOperations : DesignSurfaceElementOperations
{
public MyElementOperations(IServiceProvider serviceProvider, MyDslDiagram diagram)
: base(serviceProvider, diagram)
{ }
// Overridden methods follow
}
Recibir los elementos arrastrados de otros modelos
ElementOperations también se puede utilizar para definir la copia, el movimiento, la eliminación y el comportamiento de arrastrar y colocar.Como muestra el uso de ElementOperations, el ejemplo dado aquí define el comportamiento de arrastrar y colocar personalizado.Sin embargo, porque ese propósito podría considerar el enfoque alternativo descrito en Cómo: Agregar un controlador para arrastrar y colocar, que es más extensible.
Define dos métodos en la clase de ElementOperations:
CanMerge(ModelElement targetElement, System.Windows.Forms.IDataObject data) que determina si el elemento de origen se pueden arrastrar hasta la forma, el conector o el diagrama de destino.
MergeElementGroupPrototype(ModelElement targetElement, ElementGroupPrototype sourcePrototype) que combina el elemento de origen en el destino.
CanMerge()
[CanMerge()] se llama para determinar la información que se debe proporcionar al usuario cuando el mouse se desplaza a través del diagrama.Los parámetros del método son el elemento sobre el que el mouse se desplaza el mouse, y datos sobre el origen del que se ha realizado la operación de arrastre.El usuario puede arrastrar desde cualquier parte de la pantalla.Por consiguiente, el objeto de origen puede ser de distintos tipos y se puede serializar en diferentes formatos.Si el origen es un DSL o un modelo UML, el parámetro de datos es la serialización de ElementGroupPrototype.Las operaciones de arrastre, copy y de cuadro de herramientas usan ElementGroupPrototypes para representar fragmentos de modelos.
Un grupo Prototipos de elemento puede contener cualquier número de elementos y vínculos.Los tipos de elemento se pueden identificar por su GUID.GUID es de la forma que se arrastrada, no el elemento de modelo subyacente.En el ejemplo siguiente, CanMerge() devuelve true si una forma de clase de un diagrama UML se arrastra a este diagrama.
public override bool CanMerge(ModelElement targetShape, System.Windows.Forms.IDataObject data)
{
// Extract the element prototype from the data.
ElementGroupPrototype prototype = ElementOperations.GetElementGroupPrototype(this.ServiceProvider, data);
if (targetShape is MyTargetShape && prototype != null &&
prototype.RootProtoElements.Any(rootElement =>
rootElement.DomainClassId.ToString()
== "3866d10c-cc4e-438b-b46f-bb24380e1678")) // Guid of UML Class shapes
// or SourceClass.DomainClassId
return true;
return base.CanMerge(targetShape, data);
}
MergeElementGroupPrototype()
Se llama a este método cuando el usuario quita un elemento hasta un diagrama, una forma, o un conector.debe combinar el contenido arrastrado en el elemento de destino.En este ejemplo, el código determina si reconoce la combinación de tipos de destino y de prototipo; si se devuelve el método convierte los elementos arrastrados en un prototipo de los elementos que se deben agregar al modelo.El método base se denomina para realizar la combinación, elementos convierten o no.
public override void MergeElementGroupPrototype(ModelElement targetShape, ElementGroupPrototype sourcePrototype)
{
ElementGroupPrototype prototypeToMerge = sourcePrototype;
MyTargetShape pel = targetShape as MyTargetShape;
if (pel != null)
{
prototypeToMerge = ConvertDraggedTypeToLocal(pel, sourcePrototype);
}
if (prototypeToMerge != null)
base.MergeElementGroupPrototype(targetShape, prototypeToMerge);
}
En este ejemplo se ocupa de los elementos de la clase UML arrastrado desde un diagrama de clases UML.DSL no está diseñada para almacenar las clases UML directamente, sino, creamos un elemento ADSL para cada clase arrastrada UML.Esto sería útil, por ejemplo, si un DSL es un diagrama de instancia.El usuario puede arrastrar clases al diagrama para crear instancias de esas clases.
private ElementGroupPrototype ConvertDraggedTypeToLocal (MyTargetShape snapshot, ElementGroupPrototype prototype)
{
// Find the UML project:
EnvDTE.DTE dte = snapshot.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
foreach (EnvDTE.Project project in dte.Solution.Projects)
{
IModelingProject modelingProject = project as IModelingProject;
if (modelingProject == null) continue; // not a modeling project
IModelStore store = modelingProject.Store;
if (store == null) continue;
// Look for the shape that was dragged:
foreach (IDiagram umlDiagram in store.Diagrams())
{
// Get modeling diagram that implements UML diagram:
Diagram diagram = umlDiagram.GetObject<Diagram>();
Guid elementId = prototype.SourceRootElementIds.FirstOrDefault();
ShapeElement shape = diagram.Partition.ElementDirectory.FindElement(elementId) as ShapeElement;
if (shape == null) continue;
IClass classElement = shape.ModelElement as IClass;
if (classElement == null) continue;
// Create a prototype of elements in my DSL, based on the UML element:
Instance instance = new Instance(snapshot.Store);
instance.Type = classElement.Name;
// Pack them into a prototype:
ElementGroup group = new ElementGroup(instance);
return group.CreatePrototype();
}
}
return null;
}
Comportamiento de la operación estándar
El código de esta sección muestran que los métodos que se pueden reemplazar para modificar copiar comportamiento.Como ayuda para ver cómo lograr dispone personalizaciones, en esta sección se muestra el código que invalida los métodos necesarios para copiar, pero no cambia el comportamiento estándar.
Cuando el usuario presiona CTRL+C o usar el comando de menú copiar, se llama al método ProcessOnMenuCopyCommand .Puede ver cómo esto se establece en DslPackage\Generated Code\CommandSet.cs.Para obtener más información sobre cómo los comandos son configuración, vea Cómo: Agregar un comando a un menú contextual.
Puede reemplazar ProcessOnMenuCopyCommand agregando una definición de clase parcial de MyDslClipboardCommandSet en el proyecto de DslPackage.
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
partial class MyDslClipboardCommandSet
{
/// <summary>
/// Override ProcessOnMenuCopyCommand() to copy elements to the
/// clipboard in different formats, or to perform additional tasks
/// before or after copying – for example deselect the copied elements.
/// </summary>
protected override void ProcessOnMenuCopyCommand()
{
IList<ModelElement> selectedModelElements = this.SelectedElements;
if (selectedModelElements.Count == 0) return;
// System container for clipboard data.
// The IDataObject can contain data in several formats.
IDataObject dataObject = new DataObject();
Bitmap bitmap = null; // For export to other programs.
try
{
#region Create EGP for copying to a DSL.
this.CopyModelElementsIntoElementGroupPrototype
(dataObject, selectedModelElements);
#endregion
#region Create bitmap for copying to another application.
// Find all the shapes associated with this selection:
List<ShapeElement> shapes = new List<ShapeElement>(
this.ResolveExportedShapesForClipboardImages
(dataObject, selectedModelElements));
bitmap = this.CreateBitmapForClipboard(shapes);
if (bitmap != null)
{
dataObject.SetData(DataFormats.Bitmap, bitmap);
}
#endregion
// Add the data to the clipboard:
Clipboard.SetDataObject(dataObject, true, 5, 100);
}
finally
{
// Dispose bitmap after SetDataObject:
if (bitmap != null) bitmap.Dispose();
}
}
/// <summary>
/// Override this to customize the element group that is copied to the clipboard.
/// </summary>
protected override void CopyModelElementsIntoElementGroupPrototype(IDataObject dataObject, IList<ModelElement> selectedModelElements)
{
return this.ElementOperations.Copy(dataObject, selectedModelElements);
}
}
cada diagrama tiene una instancia singleton de ElementOperations.Puede proporcionar dispone del derivado.Este archivo, que se puede incluir en el proyecto ADSL, se comportaría igual que el código que invalida:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
namespace Company.MyDsl
{
partial class MyDslDiagram
{
/// <summary>
/// Singleton ElementOperations attached to this diagram.
/// </summary>
public override DesignSurfaceElementOperations ElementOperations
{
get
{
if (this.elementOperations == null)
{
this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
}
return this.elementOperations;
}
}
private MyElementOperations elementOperations = null;
}
// Our own version of ElementOperations so that we can override:
public class MyElementOperations : DesignSurfaceElementOperations
{
public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram)
: base(serviceProvider, diagram)
{ }
/// <summary>
/// Copy elements to the clipboard data.
/// Provides a hook for adding custom data.
/// </summary>
public override void Copy(System.Windows.Forms.IDataObject data,
ICollection<ModelElement> elements,
ClosureType closureType,
System.Drawing.PointF sourcePosition)
{
if (CanAddElementGroupFormat(elements, closureType))
{
AddElementGroupFormat(data, elements, closureType);
}
// Override these to store additional data:
if (CanAddCustomFormat(elements, closureType))
{
AddCustomFormat(data, elements, closureType, sourcePosition);
}
}
protected override void AddElementGroupFormat(System.Windows.Forms.IDataObject data, ICollection<ModelElement> elements, ClosureType closureType)
{
// Add the selected elements and those implied by the propagate copy rules:
ElementGroup elementGroup = this.CreateElementGroup(elements, closureType);
// Mark all the elements that are not embedded under other elements:
this.MarkRootElements(elementGroup, elements, closureType);
// Store in the clipboard data:
ElementGroupPrototype elementGroupPrototype = this.CreateElementGroupPrototype(elementGroup, elements, closureType);
data.SetData(ElementGroupPrototype.DefaultDataFormatName, elementGroupPrototype);
}
/// <summary>
/// Override this to store additional elements in the element group:
/// </summary>
protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType)
{
ElementGroupPrototype prototype = new ElementGroupPrototype(this.Partition, elementGroup.RootElements, elementGroup);
return prototype;
}
/// <summary>
/// Create an element group from the given starting elements, using the
/// copy propagation rules specified in the DSL Definition.
/// By default, this includes all the embedded descendants of the starting elements,
/// and also includes reference links where both ends are already included.
/// </summary>
/// <param name="startElements">model elements to copy</param>
/// <param name="closureType"></param>
/// <returns></returns>
protected override ElementGroup CreateElementGroup(ICollection<ModelElement> startElements, ClosureType closureType)
{
// ElementClosureWalker finds all the connected elements,
// according to the propagate copy rules specified in the DSL Definition:
ElementClosureWalker walker = new ElementClosureWalker(this.Partition,
closureType, // Normally ClosureType.CopyClosure
startElements,
true, // Do not load other models.
null, // Optional list of domain roles not to traverse.
true); // Include relationship links where both ends are already included.
walker.Traverse(startElements);
IList<ModelElement> closureList = walker.ClosureList;
Dictionary<object, object> closureContext = walker.Context;
// create a group for this closure
ElementGroup group = new ElementGroup(this.Partition);
group.AddRange(closureList, false);
// create the element group prototype for the group
foreach (object key in closureContext.Keys)
{
group.SourceContext.ContextInfo[key] = closureContext[key];
}
return group;
}
}
}
Vea también
Conceptos
Personalizar la creación y el movimiento de los elementos
Cómo: Agregar un controlador para arrastrar y colocar
Personalizar el comportamiento de eliminación