2008-08-26 14 views
15

¿Existe alguna manera fácil de garantizar que, después de que no se complete una acción de arrastrar y soltar, el evento MouseUp no se consuma e ignore por el marco?DoDragDrop y MouseUp

He encontrado una publicación de blog que describe one mechanism, pero implica una buena cantidad de contabilidad manual, incluidos indicadores de estado, eventos MouseMove, comprobación manual de "mouse leave", etc. que prefiero no implementar si puede ser evitado

+0

argh, me he encontrado con este problema también. Bastante molesto si me preguntas! –

Respuesta

20

Hace poco que quería poner funcionalidad Drag and Drop en mi proyecto y no me había encontrado con este problema, pero estaba intrigado y realmente quería ver si podía encontrar un método mejor que el descrito en la página a la que vinculó Espero haber comprendido claramente todo lo que quería hacer y, en general, creo que logré resolver el problema de una manera mucho más elegante y simple.

En una nota rápida, para problemas como este sería genial si proporciona algún código para que podamos ver exactamente lo que está tratando de hacer. Digo esto solo porque asumí algunas cosas sobre tu código en mi solución ... así que espero que esté bastante cerca.

Aquí está el código, lo que voy a explicar a continuación:

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

} 

He dejado fuera la mayor parte del código del diseñador, pero incluyó el enlace Gestor de Eventos Código de lo que puede estar seguro de lo que está ligada a lo que. En mi ejemplo, la función de arrastrar/soltar se produce entre las etiquetas LabelDrag y LabelDrop.

La pieza principal de mi solución es el uso del evento QueryContinueDrag. Este evento se activa cuando el estado del teclado o del mouse cambia después de que DoDragDrop ha sido llamado en ese control. Puede que ya esté haciendo esto, pero es muy importante que llame al método DoDragDrop del control que es su fuente y no al método asociado con el formulario. ¡De lo contrario, QueryContinueDrag NO se disparará!

Una cosa a tener en cuenta es que QueryContinueDrag realmente se disparará cuando suelte el mouse en el control de caída, así que tenemos que asegurarnos de que lo permitamos. Esto se controla comprobando que la posición del mouse (recuperada con la propiedad global Control.MousePosition) está dentro del rectángulo de control LabelDrop. También debe asegurarse de convertir MousePosition en un punto relativo a la ventana del cliente con PointToClient, ya que Control.MousePosition devuelve una posición relativa posición.

, mediante la comprobación de que el ratón es no sobre el control de la caída y que el botón del ratón es ahora hasta hemos capturado con eficacia un evento MouseUp para el control LabelDrag! :) Ahora, puedes hacer cualquier procesamiento que quieras hacer aquí, pero si ya tienes el código que estás usando en el controlador de eventos MouseUp, esto no es eficiente. Así que simplemente llame a su evento MouseUp desde aquí, pasándole los parámetros necesarios y el manejador MouseUp nunca sabrá la diferencia.

Sólo una nota, sin embargo, como lo llamo DoDragDrop de dentro del controlador de eventos MouseDown en mi ejemplo, este código debe nunca se consigue realmente un evento MouseUp directa al fuego. Acabo de poner ese código allí para mostrar que es posible hacerlo.

Espero que ayude!

+0

¡aprendí mucho de su solución! gracias! –

+1

¡Tu idea es genial, gracias!Pero creo que su declaración if debería verse (el botón puede estar en algo que no sea el formulario, se deshizo de espurios): if (Control.MouseButtons! = MouseButtons.Left && rect.Contains (button.Parent.PointToClient (Control) .MousePosition))) – colithium

+0

'// EXTREMADAMENTE IMPORTANTE: DEBE LLAMAR al método DoDragDrop de LabelDrag !!' ¡Muchas gracias! He estado tratando de resolver esto por horas. – Dan

Cuestiones relacionadas