2008-08-26 9 views
15

Gibt es einen einfachen Weg, um sicherzustellen, dass das MouseUp-Ereignis nach einem Drag & Drop nicht aufgefressen und vom Framework ignoriert wird?DoDragDrop und MouseUp

Ich habe einen Blogbeitrag beschrieben one mechanism, aber es beinhaltet eine gute Menge an manueller Buchhaltung, einschließlich Statusflags, MouseMove-Ereignisse, manuelle "Maus verlassen" Prüfung, usw., die ich lieber nicht implementieren müsste, wenn es kann vermieden werden.

+0

argh, ich habe in dieses Problem auch gerannt. Ziemlich nervig wenn du mich fragst! –

Antwort

20

Ich wollte vor kurzem Drag and Drop Funktionalität in mein Projekt einfügen und ich war nicht auf dieses Problem gestoßen, aber ich war fasziniert und wollte wirklich sehen, ob ich eine bessere Methode als die in beschrieben die Seite, mit der Sie verbunden sind. Ich hoffe, ich habe alles verstanden, was Sie tun wollten, und ich denke, es ist mir gelungen, das Problem viel eleganter und einfacher zu lösen.

Kurz gesagt, für solche Probleme wäre es großartig, wenn Sie Code zur Verfügung stellen, damit wir genau sehen können, was Sie zu tun versuchen. Ich sage das nur, weil ich in meiner Lösung ein paar Dinge über deinen Code angenommen habe ... also hoffentlich ist es ziemlich nah dran.

Hier ist der Code, die ich weiter unten erklären:

this.LabelDrag.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.LabelDrag_QueryContinueDrag); 
this.LabelDrag.MouseDown += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseDown); 
this.LabelDrag.MouseUp += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseUp); 

this.LabelDrop.DragDrop += new System.Windows.Forms.DragEventHandler(this.LabelDrop_DragDrop); 
this.LabelDrop.DragEnter += new System.Windows.Forms.DragEventHandler(this.LabelMain_DragEnter); 

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void LabelDrop_DragDrop(object sender, DragEventArgs e) 
    { 
     LabelDrop.Text = e.Data.GetData(DataFormats.Text).ToString(); 
    } 


    private void LabelMain_DragEnter(object sender, DragEventArgs e) 
    { 
     if (e.Data.GetDataPresent(DataFormats.Text)) 
      e.Effect = DragDropEffects.Copy; 
     else 
      e.Effect = DragDropEffects.None; 

    } 

    private void LabelDrag_MouseDown(object sender, MouseEventArgs e) 
    { 
     //EXTREMELY IMPORTANT - MUST CALL LabelDrag's DoDragDrop method!! 
     //Calling the Form's DoDragDrop WILL NOT allow QueryContinueDrag to fire! 
     ((Label)sender).DoDragDrop(TextMain.Text, DragDropEffects.Copy); 
    } 

    private void LabelDrag_MouseUp(object sender, MouseEventArgs e) 
    { 
     LabelDrop.Text = "LabelDrag_MouseUp"; 
    } 

    private void LabelDrag_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) 
    { 
     //Get rect of LabelDrop 
     Rectangle rect = new Rectangle(LabelDrop.Location, new Size(LabelDrop.Width, LabelDrop.Height)); 

     //If the left mouse button is up and the mouse is not currently over LabelDrop 
     if (Control.MouseButtons != MouseButtons.Left && !rect.Contains(PointToClient(Control.MousePosition))) 
     { 
      //Cancel the DragDrop Action 
      e.Action = DragAction.Cancel; 
      //Manually fire the MouseUp event 
      LabelDrag_MouseUp(sender, new MouseEventArgs(Control.MouseButtons, 0, Control.MousePosition.X, Control.MousePosition.Y, 0)); 
     } 
    } 

} 

Ich habe die meisten der Designer-Code weggelassen, aber enthalten die Event-Handler-Link Up-Code, so können Sie sicher sein, was zu dem, was verbunden ist. In meinem Beispiel findet der Drag/Drop zwischen den Labels LabelDrag und LabelDrop statt.

Der Hauptteil meiner Lösung ist die Verwendung des QueryContinueDrag-Ereignisses. Dieses Ereignis wird ausgelöst, wenn sich der Tastatur- oder Mausstatus ändert, nachdem DoDragDrop für dieses Steuerelement aufgerufen wurde. Möglicherweise tun Sie dies bereits, aber es ist sehr wichtig, dass Sie die DoDragDrop-Methode des Steuerelements aufrufen, das Ihre Quelle und nicht die mit dem Formular verknüpfte Methode ist. Sonst wird QueryContinueDrag NICHT ausgelöst!

Eine Sache zu beachten ist, dass QueryContinueDrag tatsächlich ausgelöst wird, wenn Sie die Maus auf die Drop-Steuerelement freigeben, so müssen wir dafür sorgen, dass wir dies zulassen. Dies wird dadurch erledigt, dass überprüft wird, ob die Mausposition (die mit der globalen Control.MousePosition-Eigenschaft abgerufen wurde) innerhalb des LabelDrop-Kontrollrechtecks ​​liegt. Sie müssen außerdem sicherstellen, dass MousePosition in einen Punkt relativ zum Clientfenster mit PointToClient konvertiert wird, da Control.MousePosition eine Bildschirmposition relativ zurückgibt.

So durch Überprüfen, dass die Maus nicht über die Drop-Steuerung ist und dass die Maustaste ist jetzt bis wir ein Ereignis MouseUp für die LabelDrag Kontrolle effektiv erfasst haben! :) Jetzt können Sie einfach die von Ihnen gewünschte Verarbeitung ausführen, aber wenn Sie bereits Code im MouseUp Event-Handler verwenden, ist dies nicht effizient. Rufen Sie einfach von hier aus Ihr MouseUp-Ereignis auf, übergeben Sie ihm die notwendigen Parameter, und der MouseUp-Handler wird den Unterschied nie erkennen.

Nur wenn Note, wie ich DoDragDrop von innerhalb der MouseDown- Ereignishandler in meinem Beispiel nennen, dieser Code sollte nie bekommt tatsächlich ein direktes MouseUp-Ereignis ausgelöst. Ich habe diesen Code einfach eingefügt, um zu zeigen, dass es möglich ist.

Hoffe, dass hilft!

+0

hat viel von Ihrer Lösung gelernt! danke! –

+1

Ihre Idee ist großartig, danke!Aber ich denke, deine if-Anweisung sollte wie folgt aussehen (Button kann in etwas anderem als der Form sein, wurde von false nicht los): if (Control.MouseButtons! = MouseButtons.Left && rect.Contains (button.Parent.PointToClient (Control .MousePosition))) – colithium

+0

'// EXTREM WICHTIG - MUSS die DoDragDrop-Methode von LabelDrag aufrufen!' Vielen Dank! Ich habe versucht, das stundenlang herauszufinden. – Dan

Verwandte Themen