DoDragDrop и MouseUp

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

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

Ответы

Ответ 1

Недавно я захотел установить функциональность 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 DoDragDrop method!!
        //Calling the Form 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));
        }
    }

}

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

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

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

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

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

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