Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Anda dapat menambahkan handler untuk peristiwa seret dan letakkan ke DSL Anda, sehingga pengguna dapat menyeret item ke diagram Anda dari diagram lain atau dari bagian lain Visual Studio. Anda juga dapat menambahkan handler untuk peristiwa seperti klik dua kali. Bersama-sama, handler seret dan letakkan dan klik dua kali dikenal sebagai handler gerakan.
Topik ini membahas gerakan seret dan letakkan yang berasal dari diagram lain. Untuk memindahkan dan menyalin peristiwa dalam satu diagram, pertimbangkan alternatif untuk menentukan subkelas dari ElementOperations. Untuk informasi selengkapnya, lihat Menyesuaikan Perilaku Salin. Anda mungkin juga dapat menyesuaikan definisi DSL.
Menentukan Handler Gerakan dengan Mengambil Alih Metode ShapeElement
OnDragDrop, OnDoubleClick, OnDragOver, dan metode lainnya dapat diambil alih.
Tambahkan file kode baru ke proyek DSL Anda. Untuk handler gerakan, Anda biasanya harus memiliki setidaknya arahan using berikut:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Linq;
Di file baru, tentukan kelas parsial untuk kelas bentuk atau diagram yang harus merespons operasi seret. Ambil alih metode berikut:
OnDragOver- Metode ini dipanggil saat pointer mouse memasuki bentuk selama operasi seret. Metode Anda harus memeriksa item yang diseret pengguna, dan mengatur properti Efek untuk menunjukkan apakah pengguna dapat meletakkan item pada bentuk ini. Properti Efek menentukan tampilan kursor saat berada di atas bentuk ini, dan juga menentukan apakah
OnDragDrop()akan dipanggil saat pengguna melepaskan tombol mouse.partial class MyShape // MyShape generated from DSL Definition. { public override void OnDragOver(DiagramDragEventArgs e) { base.OnDragOver(e); if (e.Effect == System.Windows.Forms.DragDropEffects.None && IsAcceptableDropItem(e)) // To be defined { e.Effect = System.Windows.Forms.DragDropEffects.Copy; } }OnDragDrop - Metode ini dipanggil jika pengguna melepaskan tombol mouse saat pointer mouse berada di atas bentuk atau diagram ini, jika
OnDragOver(DiagramDragEventArgs e)sebelumnya diature.Effectke nilai selainNone.public override void OnDragDrop(DiagramDragEventArgs e) { if (!IsAcceptableDropItem(e)) { base.OnDragDrop(e); } else { // Process the dragged item, for example merging a copy into the diagram ProcessDragDropItem(e); // To be defined } }OnDoubleClick - Metode ini dipanggil saat pengguna mengeklik dua kali bentuk atau diagram.
Untuk informasi selengkapnya, lihat Cara: Menahan Klik pada Bentuk atau Dekorator.
Tentukan IsAcceptableDropItem(e) untuk menentukan apakah item yang diseret dapat diterima, dan ProcessDragDropItem(e) untuk memperbarui model Anda saat item diletakkan. Metode ini harus terlebih dahulu mengekstrak item dari argumen peristiwa. Untuk informasi tentang cara melakukannya, lihat Cara mendapatkan referensi ke item yang diseret.
Menentukan Handler Gerakan menggunakan MEF
Gunakan metode ini jika Anda ingin pengembang pihak ketiga dapat menentukan handler mereka sendiri untuk DSL Anda. Pengguna dapat memilih untuk menginstal ekstensi pihak ketiga setelah mereka menginstal DSL Anda.
MEF (Managed Extensibility Framework) memungkinkan Anda menentukan komponen yang dapat diinstal dengan konfigurasi minimal. Untuk informasi selengkapnya, lihat Kerangka Kerja Ekstensibilitas Terkelola (MEF).
Untuk menentukan handler gerakan MEF
Tambahkan ke proyek Dsl dan DslPackage Anda file MefExtension yang dijelaskan dalam Memperpanjang DSL Anda menggunakan MEF.
Anda sekarang dapat menentukan handler gerakan sebagai komponen MEF:
// This attribute is defined in the generated file // DslPackage\MefExtension\DesignerExtensionMetaDataAttribute.cs: [MyDslGestureExtension] public class MyGestureHandlerClassName : IGestureExtension { /// <summary> /// Called to determine whether a drag onto the diagram can be accepted. /// </summary> /// <param name="diagramDragEventArgs">Contains a link to the item that is being dragged</param> /// <param name="targetMergeElement">The shape or connector that the mouse is over</param> /// <returns>True if the item can be accepted on the targetMergeElement.</returns> public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs) { MyShape target = targetMergeElement as MyShape; if (target == null) return false; if (target.IsAcceptableDropItem(diagramDragEventArgs)) return true; return false; } public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs) { MyShape target = targetMergeElement as MyShape; if (target == null || ! target.IsAcceptableDropItem(diagramDragEventArgs)) return; // Process the dragged item, for example merging a copy into the diagram: target.ProcessDragDropItem(diagramDragEventArgs); }Anda dapat membuat lebih dari satu komponen handler gerakan, seperti saat Anda memiliki berbagai jenis objek yang diseret.
Tambahkan definisi kelas parsial untuk bentuk target, konektor atau kelas diagram, dan tentukan metode
IsAcceptableDropItem()danProcessDragDropItem(). Metode ini harus dimulai dengan mengekstrak item yang diseret dari argumen peristiwa. Untuk informasi selengkapnya, lihat Cara mendapatkan referensi ke item yang diseret.
Cara mendekode item yang diseret
Elemen dapat diseret dari jendela mana pun atau dari desktop, serta dari DSL.
Saat pengguna menyeret item ke diagram Anda, atau dari satu bagian diagram ke bagian lain, informasi tentang item yang sedang diseret tersedia di DiagramDragEventArgs. Karena operasi seret dapat dimulai pada objek apa pun di layar, data dapat tersedia dalam salah satu dari berbagai format. Kode Anda harus mengenali format yang dapat ditanganinya.
Untuk menemukan format tempat informasi sumber seret Anda tersedia, jalankan kode Anda dalam mode debug, atur titik henti sementara pada entri ke OnDragOver() atau CanDragDrop(). Periksa nilai parameter DiagramDragEventArgs. Informasi diberikan dalam dua bentuk:
IDataObject
Data- Properti ini membawa versi berseri objek sumber, biasanya dalam lebih dari satu format. Fungsinya yang paling berguna adalah:diagramEventArgs.Data.GetDataFormats() - Mencantumkan format tempat Anda dapat mendekode objek yang diseret. Misalnya, jika pengguna menyeret file dari desktop, format yang tersedia akan menyertakan nama file ("
FileNameW").diagramEventArgs.Data.GetData(format)- Mendekode objek yang diseret dalam format yang ditentukan. Transmisikan objek ke jenis yang sesuai. Contohnya:string fileName = diagramEventArgs.Data.GetData("FileNameW") as string;Anda juga dapat mengirimkan objek seperti referensi bus model dari sumber dalam format kustom Anda sendiri. Untuk informasi selengkapnya, lihat Cara Mengirim Model Bus Reference di Seret dan Letakkan.
ElementGroupPrototype
Prototype- Gunakan properti ini jika Anda ingin pengguna menyeret item dari model DSL atau UML. Prototipe grup elemen berisi satu atau beberapa objek, tautan, dan nilai propertinya. Ini juga digunakan dalam operasi tempel dan saat Anda menambahkan elemen dari kotak alat. Dalam prototipe, objek dan jenisnya diidentifikasi oleh Guid. Misalnya, kode ini memungkinkan pengguna untuk menyeret elemen kelas dari diagram UML atau UML Model Explorer:private bool IsAcceptableDropItem(DiagramDragEventArgs e) { return e.Prototype != null && e.Prototype.RootProtoElements.Any(element => element.DomainClassId.ToString() == "3866d10c-cc4e-438b-b46f-bb24380e1678"); // Accept UML class shapes. // Or, from another DSL: SourceNamespace.SourceShapeClass.DomainClassId }Untuk menerima bentuk UML, tentukan GUID kelas bentuk UML dengan eksperimen. Ingatlah bahwa biasanya ada lebih dari satu jenis elemen pada diagram apa pun. Ingat juga bahwa objek yang diseret dari diagram DSL atau UML adalah bentuknya, bukan elemen modelnya.
DiagramDragEventArgs juga memiliki properti yang menunjukkan posisi pointer mouse saat ini dan apakah pengguna menekan tombol CTRL, ALT, atau SHIFT.
Cara mendapatkan yang asli dari elemen yang diseret
Jika item yang diseret adalah elemen DSL, Anda dapat membuka model sumber dan mengakses elemen tersebut.
Properti Data dan Prototype dari argumen peristiwa hanya berisi referensi ke bentuk yang diseret. Biasanya, jika Anda ingin membuat objek di DSL target yang diturunkan dari prototipe dalam beberapa cara, Anda perlu mendapatkan akses ke aslinya, misalnya, membaca konten file, atau menavigasi ke elemen model yang diwakili oleh bentuk. Anda dapat menggunakan Visual Studio Model Bus untuk membantu dengan ini.
Untuk menyiapkan proyek DSL untuk Model Bus
Jadikan sumber DSL dapat diakses oleh Visual Studio Model Bus:
Buka file definisi DSL dari sumber DSL di Perancang DSL. Klik kanan permukaan desain, kemudian klik Aktifkan Modelbus. Di kotak dialog, pilih salah satu atau kedua opsi. Klik OK. Proyek baru "ModelBus" ditambahkan ke solusi DSL.
Klik Ubah Semua Templat dan bangun kembali solusinya.
Untuk mengirim objek dari DSL sumber
Di subkelas ElementOperations Anda, ambil alih
Copy()sehingga mengodekan Model Bus Reference (MBR) ke dalam IDataObject. Metode ini akan dipanggil ketika pengguna mulai menyeret dari diagram sumber. MBR yang dikodekan kemudian akan tersedia di IDataObject ketika pengguna meletakkan di diagram target.using Microsoft.VisualStudio.Modeling; using Microsoft.VisualStudio.Modeling.Shell; using Microsoft.VisualStudio.Modeling.Diagrams; using Microsoft.VisualStudio.Modeling.Integration; using Microsoft.VisualStudio.Modeling.Integration.Shell; using System.Drawing; // PointF using System.Collections.Generic; // ICollection using System.Windows.Forms; // for IDataObject ... public class MyElementOperations : DesignSurfaceElementOperations { public override void Copy(System.Windows.Forms.IDataObject data, System.Collections.Generic.ICollection<ModelElement> elements, ClosureType closureType, System.Drawing.PointF sourcePosition) { base.Copy(data, elements, closureType, sourcePosition); // Get the ModelBus service: IModelBus modelBus = this.Store.GetService(typeof(SModelBus)) as IModelBus; DocData docData = ((VSDiagramView)this.Diagram.ActiveDiagramView).DocData; string modelFile = docData.FileName; // Get an adapterManager for the target DSL: ModelBusAdapterManager manager = (modelBus.FindAdapterManagers(modelFile).First()); ModelBusReference modelReference = manager.CreateReference(modelFile); ModelBusReference elementReference = null; using (ModelBusAdapter adapter = modelBus.CreateAdapter(modelReference)) { elementReference = adapter.GetElementReference(elements.First()); } data.SetData("ModelBusReference", elementReference); } ...}
Untuk menerima Model Bus Reference dari DSL dalam proyek DSL atau UML target
Dalam proyek DSL target, tambahkan referensi proyek ke:
Proyek Dsl sumber.
Proyek ModelBus sumber.
Dalam file kode handler gerakan, tambahkan referensi namespace layanan berikut:
using Microsoft.VisualStudio.Modeling; using Microsoft.VisualStudio.Modeling.ExtensionEnablement; using Microsoft.VisualStudio.Modeling.Diagrams; using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; using Microsoft.VisualStudio.Modeling.Integration; using SourceDslNamespace; using SourceDslNamespace.ModelBusAdapters;Contoh berikut menggambarkan cara mendapatkan akses ke elemen model sumber:
partial class MyTargetShape // or diagram or connector { internal void ProcessDragDropItem(DiagramDragEventArgs diagramDragEventArgs) { // Verify that we're being passed an Object Shape. ElementGroupPrototype prototype = diagramDragEventArgs.Prototype; if (prototype == null) return; if (Company.InstanceDiagrams.ObjectShape.DomainClassId != prototype.RootProtoElements.First().DomainClassId) return; // - This is an ObjectShape. // - We need to access the originating Store, find the shape, and get its object. IModelBus modelBus = targetDropElement.Store.GetService(typeof(SModelBus)) as IModelBus; // Unpack the MBR that was packed in Copy: ModelBusReference reference = diagramDragEventArgs.Data.GetData("ModelBusReference") as ModelBusReference; using (SourceDslAdapter adapter = modelBus.CreateAdapter(reference) as SourceDslAdapter) { using (ILinkedUndoTransaction t = LinkedUndoContext.BeginTransaction("doing things")) { // Quickest way to get the shape from the MBR: ObjectShape firstShape = adapter.ResolveElementReference<ObjectShape>(reference); // But actually there might be several shapes - so get them from the prototype instead: IElementDirectory remoteDirectory = adapter.Store.ElementDirectory; foreach (Guid shapeGuid in prototype.SourceRootElementIds) { PresentationElement pe = remoteDirectory.FindElement(shapeGuid) as PresentationElement; if (pe == null) continue; SourceElement instance = pe.ModelElement as SourceElement; if (instance == null) continue; // Do something with the object: instance... } t.Commit(); } } }
Untuk menerima elemen yang bersumber dari model UML
Contoh kode berikut menerima objek yang diletakkan dari diagram UML.
using Microsoft.VisualStudio.ArchitectureTools.Extensibility; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation; using Microsoft.VisualStudio.Modeling; using Microsoft.VisualStudio.Modeling.Diagrams; using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; using Microsoft.VisualStudio.Uml.Classes; using System; using System.ComponentModel.Composition; using System.Linq; ... partial class TargetShape { internal void ProcessDragDropItem(DiagramDragEventArgs diagramDragEventArgs) { EnvDTE.DTE dte = this.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE; // Find the UML project 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) return; foreach (IDiagram dd in store.Diagrams()) { // Get Modeling.Diagram that implements UML.IDiagram: Diagram diagram = dd.GetObject<Diagram>(); foreach (Guid elementId in e.Prototype.SourceRootElementIds) { ShapeElement shape = diagram.Partition.ElementDirectory.FindElement(elementId) as ShapeElement; if (shape == null) continue; // This example assumes the shape is a UML class: IClass classElement = shape.ModelElement as IClass; if (classElement == null) continue; // Now do something with the UML class element ... } } break; // don't try any more projects } } }
Menggunakan Tindakan Mouse: Menyeret Item Kompartemen
Anda dapat menulis handler yang menahan tindakan mouse pada bidang bentuk. Contoh berikut memungkinkan pengguna menyusun ulang item dalam kompartemen dengan menyeret dengan mouse.
Untuk membangun contoh ini, buat solusi menggunakan templat solusi Diagram Kelas. Tambahkan file kode dan tambahkan kode berikut. Sesuaikan namespace layanan agar sama dengan milik Anda.
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Design;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Collections.Generic;
using System.Linq;
// This sample allows users to re-order items in a compartment shape by dragging.
// This example is built on the "Class Diagrams" solution template of VMSDK (DSL Tools).
// You will need to change the following domain class names to your own:
// ClassShape = a compartment shape
// ClassModelElement = the domain class displayed using a ClassShape
// This code assumes that the embedding relationships displayed in the compartments
// don't use inheritance (don't have base or derived domain relationships).
namespace Company.CompartmentDrag // EDIT.
{
/// <summary>
/// Manage the mouse while dragging a compartment item.
/// </summary>
public class CompartmentDragMouseAction : MouseAction
{
private ModelElement sourceChild;
private ClassShape sourceShape;
private RectangleD sourceCompartmentBounds;
public CompartmentDragMouseAction(ModelElement sourceChildElement, ClassShape sourceParentShape, RectangleD bounds)
: base (sourceParentShape.Diagram)
{
sourceChild = sourceChildElement;
sourceShape = sourceParentShape;
sourceCompartmentBounds = bounds; // For cursor.
}
/// <summary>
/// Call back to the source shape to drop the dragged item.
/// </summary>
/// <param name="e"></param>
protected override void OnMouseUp(DiagramMouseEventArgs e)
{
base.OnMouseUp(e);
sourceShape.DoMouseUp(sourceChild, e);
this.Cancel(e.DiagramClientView);
e.Handled = true;
}
/// <summary>
/// Ideally, this shouldn't happen. This action should only be active
/// while the mouse is still pressed. However, it can happen if you
/// move the mouse rapidly out of the source shape, let go, and then
/// click somewhere else in the source shape. Yuk.
/// </summary>
/// <param name="e"></param>
protected override void OnMouseDown(DiagramMouseEventArgs e)
{
base.OnMouseDown(e);
this.Cancel(e.DiagramClientView);
e.Handled = false;
}
/// <summary>
/// Display an appropriate cursor while the drag is in progress:
/// Up-down arrow if we are inside the original compartment.
/// No entry if we are elsewhere.
/// </summary>
/// <param name="currentCursor"></param>
/// <param name="diagramClientView"></param>
/// <param name="mousePosition"></param>
/// <returns></returns>
public override System.Windows.Forms.Cursor GetCursor(System.Windows.Forms.Cursor currentCursor, DiagramClientView diagramClientView, PointD mousePosition)
{
// If the cursor is inside the original compartment, show up-down cursor.
return sourceCompartmentBounds.Contains(mousePosition)
? System.Windows.Forms.Cursors.SizeNS // Up-down arrow.
: System.Windows.Forms.Cursors.No;
}
}
/// <summary>
/// Override some methods of the compartment shape.
/// *** GenerateDoubleDerived must be set for this shape in DslDefinition.dsl. ****
/// </summary>
public partial class ClassShape
{
/// <summary>
/// Model element that is being dragged.
/// </summary>
private static ClassModelElement dragStartElement = null;
/// <summary>
/// Absolute bounds of the compartment, used to set the cursor.
/// </summary>
private static RectangleD compartmentBounds;
/// <summary>
/// Attach mouse listeners to the compartments for the shape.
/// This is called once per compartment shape.
/// The base method creates the compartments for this shape.
/// </summary>
public override void EnsureCompartments()
{
base.EnsureCompartments();
foreach (Compartment compartment in this.NestedChildShapes.OfType<Compartment>())
{
compartment.MouseDown += new DiagramMouseEventHandler(compartment_MouseDown);
compartment.MouseUp += new DiagramMouseEventHandler(compartment_MouseUp);
compartment.MouseMove += new DiagramMouseEventHandler(compartment_MouseMove);
}
}
/// <summary>
/// Remember which item the mouse was dragged from.
/// We don't create an Action immediately, as this would inhibit the
/// inline text editing feature. Instead, we just remember the details
/// and will create an Action when/if the mouse moves off this list item.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void compartment_MouseDown(object sender, DiagramMouseEventArgs e)
{
dragStartElement = e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault();
compartmentBounds = e.HitDiagramItem.Shape.AbsoluteBoundingBox;
}
/// <summary>
/// When the mouse moves away from the initial list item, but still inside the compartment,
/// create an Action to supervise the cursor and handle subsequent mouse events.
/// Transfer the details of the initial mouse position to the Action.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void compartment_MouseMove(object sender, DiagramMouseEventArgs e)
{
if (dragStartElement != null)
{
if (dragStartElement != e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault())
{
e.DiagramClientView.ActiveMouseAction = new CompartmentDragMouseAction(dragStartElement, this, compartmentBounds);
dragStartElement = null;
}
}
}
/// <summary>
/// User has released the mouse button.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void compartment_MouseUp(object sender, DiagramMouseEventArgs e)
{
dragStartElement = null;
}
/// <summary>
/// Forget the source item if mouse up occurs outside the
/// compartment.
/// </summary>
/// <param name="e"></param>
public override void OnMouseUp(DiagramMouseEventArgs e)
{
base.OnMouseUp(e);
dragStartElement = null;
}
/// <summary>
/// Called by the Action when the user releases the mouse.
/// If we are still on the same compartment but in a different list item,
/// move the starting item to the position of the current one.
/// </summary>
/// <param name="dragFrom"></param>
/// <param name="e"></param>
public void DoMouseUp(ModelElement dragFrom, DiagramMouseEventArgs e)
{
// Original or "from" item:
ClassModelElement dragFromElement = dragFrom as ClassModelElement;
// Current or "to" item:
ClassModelElement dragToElement = e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault();
if (dragFromElement != null && dragToElement != null)
{
// Find the common parent model element, and the relationship links:
ElementLink parentToLink = GetEmbeddingLink(dragToElement);
ElementLink parentFromLink = GetEmbeddingLink(dragFromElement);
if (parentToLink != parentFromLink && parentFromLink != null && parentToLink != null)
{
// Get the static relationship and role (= end of relationship):
DomainRelationshipInfo relationshipFrom = parentFromLink.GetDomainRelationship();
DomainRoleInfo parentFromRole = relationshipFrom.DomainRoles[0];
// Get the node in which the element is embedded, usually the element displayed in the shape:
ModelElement parentFrom = parentFromLink.LinkedElements[0];
// Same again for the target:
DomainRelationshipInfo relationshipTo = parentToLink.GetDomainRelationship();
DomainRoleInfo parentToRole = relationshipTo.DomainRoles[0];
ModelElement parentTo = parentToLink.LinkedElements[0];
// Mouse went down and up in same parent and same compartment:
if (parentTo == parentFrom && relationshipTo == relationshipFrom)
{
// Find index of target position:
int newIndex = 0;
var elementLinks = parentToRole.GetElementLinks(parentTo);
foreach (ElementLink link in elementLinks)
{
if (link == parentToLink) { break; }
newIndex++;
}
if (newIndex < elementLinks.Count)
{
using (Transaction t = parentFrom.Store.TransactionManager.BeginTransaction("Move list item"))
{
parentFromLink.MoveToIndex(parentFromRole, newIndex);
t.Commit();
}
}
}
}
}
}
/// <summary>
/// Get the embedding link to this element.
/// Assumes there is no inheritance between embedding relationships.
/// (If there is, you need to make sure you've got the relationship
/// that is represented in the shape compartment.)
/// </summary>
/// <param name="child"></param>
/// <returns></returns>
ElementLink GetEmbeddingLink(ClassModelElement child)
{
foreach (DomainRoleInfo role in child.GetDomainClass().AllEmbeddedByDomainRoles)
{
foreach (ElementLink link in role.OppositeDomainRole.GetElementLinks(child))
{
// Just the assume the first embedding link is the only one.
// Not a valid assumption if one relationship is derived from another.
return link;
}
}
return null;
}
}
}
Konten terkait
Catatan
Komponen Transformasi Template Teks secara otomatis diinstal sebagai bagian dari beban kerja pengembangan ekstensi Visual Studio. Anda juga dapat menginstalnya dari tab Komponen individual Alat Penginstal Visual Studio, di bawah kategori SDK, pustaka, dan kerangka kerja. Instal komponen SDK Pemodelan dari tab Komponen individual.