DoDragDrop и MouseUp - PullRequest
       17

DoDragDrop и MouseUp

16 голосов
/ 27 августа 2008

Есть ли простой способ гарантировать, что после сбоя перетаскивания событие MouseUp не будет съедено и проигнорировано платформой?

Я нашел сообщение в блоге, описывающее один механизм , но в нем много ручного бухгалтерии, включая флаги состояния, события MouseMove, ручную проверку "отпускания мыши" и т. Д. скорее не нужно реализовывать, если этого можно избежать.

1 Ответ

22 голосов
/ 27 августа 2008

Недавно я хотел добавить функциональность Drag and Drop в свой проект, и я не сталкивался с этой проблемой, но я был заинтригован и очень хотел посмотреть, смогу ли я найти лучший метод, чем тот, который описан в страница, на которую вы ссылаетесь. Я надеюсь, что я ясно понял все, что вы хотели сделать, и в целом, мне кажется, мне удалось решить проблему гораздо более элегантно и просто.

Вкратце: для таких проблем было бы неплохо, если бы вы предоставили некоторый код, чтобы мы могли точно видеть, что именно вы пытаетесь сделать. Я говорю это только потому, что предположил несколько вещей о вашем коде в своем решении ... так что, надеюсь, он довольно близок.

Вот код, который я объясню ниже:

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

}

Я пропустил большую часть кода дизайнера, но включил код связи обработчика событий, чтобы вы могли быть уверены, что связано с чем. В моем примере перетаскивание происходит между метками LabelDrag и LabelDrop.

Основной частью моего решения является использование события QueryContinueDrag. Это событие возникает, когда состояние клавиатуры или мыши изменяется после вызова DoDragDrop для этого элемента управления. Возможно, вы уже делаете это, но очень важно, чтобы вы вызвали метод DoDragDrop элемента управления, который является вашим источником, а не метод, связанный с формой. В противном случае QueryContinueDrag НЕ сработает!

Следует отметить, что QueryContinueDrag действительно будет срабатывать при отпускании мыши на элементе управления отпуском , поэтому нам нужно убедиться, что мы это допустим. Это выполняется путем проверки того, что позиция Mouse (полученная с помощью глобального свойства Control.MousePosition) находится внутри прямоугольника элемента управления LabelDrop. Также необходимо обязательно преобразовать MousePosition в точку относительно окна клиента с помощью PointToClient, поскольку Control.MousePosition возвращает экран относительно позиции .

Итак, проверив, что мышь не над элементом управления drop и что кнопка мыши теперь up , мы эффективно захватили событие MouseUp для элемента управления LabelDrag! :) Теперь вы можете просто выполнить любую обработку, которую вы хотите сделать здесь, но если у вас уже есть код, который вы используете в обработчике события MouseUp, это неэффективно. Поэтому просто вызовите событие MouseUp отсюда, передав ему необходимые параметры, и обработчик MouseUp никогда не узнает разницу.

Просто примечание, так как я вызываю DoDragDrop из в обработчике события MouseDown в моем примере, этот код должен никогда фактически получать прямое событие MouseUp для запуска. Я просто вставил туда этот код, чтобы показать, что это возможно.

Надеюсь, это поможет!

...