DragDrop - DragEnter / DragLeave События продолжают срабатывать - PullRequest
13 голосов
/ 14 апреля 2010

У меня есть операция перетаскивания на Canvas, которая должна что-то делать, когда объект перетаскивается в него и из него. Моя проблема в том, что события DragEnter / DragLeave продолжают срабатывать, когда мышь перемещает объект над ним, а не только при входе / выходе. Чем быстрее движется мышь, тем чаще происходят события.

Событие Canvas DragOver перемещает Canvas.Top/Left DraggedObject, и я думаю, что это может быть моей проблемой, но я не уверен, как бы это исправить.

Ответы [ 5 ]

17 голосов
/ 14 апреля 2010

Вот последовательность событий:

  1. Ваша мышь перемещается от того места, где вы щелкнули ее по всей панели. Нет событий пожара.
  2. Ваша мышь достигает края панели и входит в холст. Событие DragEnter происходит на Холсте.
  3. Ваш обработчик DragEnter перемещает панель так, что теперь она находится под мышью. Поскольку мышь больше не находится над Canvas (она находится над панелью), происходит событие DragLeave.
  4. Ваша мышь двигается дальше, снова достигая края панели. Шаги 2 и 3 повторяются.

Чем быстрее вы двигаете мышь, тем больше событий вы получите.

Суть вашей проблемы заключается в том, что при перетаскивании используется проверка на попадание, и, перемещая панель, вы теряете способность проверки на попадание, чтобы видеть «за» панелью, чтобы узнать, в какой контейнер она сбрасывается.

Решение состоит в том, чтобы использовать собственный код для обработки перетаскивания, что на самом деле совсем не сложно. Механизм тестирования попаданий в WPF достаточно мощный, чтобы выполнять проверку попаданий за текущим объектом, но перетаскивание не использует эту функциональность. Однако вы можете использовать его напрямую, используя перегрузку VisualTreeHelper.HitTest, которая принимает HitTestFilterCallback и HitTestResultCallback. Просто пропустите фильтр, который игнорирует любые попадания в пределах перетаскиваемой панели.

Я обнаружил, что для таких сценариев, как вы описываете, перетаскивание с помощью обработки событий мыши на самом деле проще, чем использование встроенного DoDragDrop, потому что вам не нужно иметь дело со сложностью (DataObject, DragDropEffects, QueryContinueDrag и т. Д.). ). Эта дополнительная сложность очень важна для включения сценариев перетаскивания между приложениями и процессами, но не помогает вам в том, что вы делаете.

Вот простое решение:

  1. При MouseDown левой кнопкой вниз записать положение (при MouseLeave стереть положение)
  2. В MouseMove с {левой кнопкой вниз, записанным положением, текущим положением мыши отличается более чем на дельту}, установите флаг о том, что операция перетаскивания выполняется, и захватите мышь
  3. В MouseMove с выполняемой операцией перетаскивания используйте тестирование нажатия, чтобы определить, где должна находиться ваша панель (игнорируя саму панель), и соответственно отрегулируйте ее родительские элементы и положение.
  4. В MouseUp с выполняемой операцией перетаскивания отпустите захват мыши и снимите флажок «Операция перетаскивания»

Наслаждайтесь.

2 голосов
/ 02 сентября 2015

Это немного старовато, но у меня была та же проблема. Я использовал рекламный указатель, чтобы указать, куда перетаскивают перетаскиваемый предмет. Я бы включил рекламодателя в DragEnter, затем сразу зарегистрировал DragLeave и отключил рекламодателя, затем DragEnter ...

IsEnabled = false не работал для меня, но IsHitTestVisible = false работал. Я поместил это в конструктор моего автора, и теперь все это прекрасно работает:

public DragDropAdorner(UIElement adornedElement) : base(adornedElement)
{
    _layer = AdornerLayer.GetAdornerLayer(AdornedElement);
    _layer.IsEnabled = false;
    _layer.IsHitTestVisible = false;
}
1 голос
/ 07 февраля 2019

У меня недавно была похожая проблема, хотя она была в рамках Angular 6 с использованием реактивных форм. Вот как я решил это для моей ситуации:

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

  1. import ChangeDetectorRef:
    import { ChangeDetectorRef } from '@angular/core';
  1. вставьте его в конструктор:
    constructor(private chngDetRef: ChangeDetectorRef) { //...
  1. отключить его на dragStart:
    private onDragStart(event, dragSource, dragIndex) {
        // ...
        this.chngDetRef.detach();
        // ...
  1. подключите его и перетащите.
    private onDrop(event, dragSource, dragIndex) {
        // ...
        this.chngDetRef.reattach();
        // ...

    private onDragEnd(event, dragIndex) {
        // ...
        this.chngDetRef.reattach();
        // ...

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

Удачи!

0 голосов
/ 16 августа 2018

У меня была похожая проблема, и магия, которая исправила ее, была e.Handled = true;

Я хотел выбрать TabItem, когда над ним что-то перетаскивали. Это мое решение.

В словаре ресурсов определите:

<Style TargetType="TabItem">
    <Setter Property="AllowDrop" Value="True" />
    <EventSetter Event="DragEnter" Handler="tabDragEnter" />
    <EventSetter Event="DragOver" Handler="tabDragOver" />
</Style>

Тогда обработчик tabDragEnter:

private void tabDragEnter(object sender, DragEventArgs e)
    {            
        TabItem m_TabItem = sender as TabItem;
        m_TabItem.IsSelected = true;
    }

и, наконец, обработчик tabDragOver:

private void tabDragOver(object sender, DragEventArgs e)
    {
        e.Effects = DragDropEffects.None;
        e.Handled = true;
    }
0 голосов
/ 10 августа 2015

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

Хорошо, вот что происходит:

  1. Вы создаете операцию перетаскивания.
  2. Во время перетаскивания вы хотите, чтобы что-то визуальное показывалось вдоль вашей мыши.
  3. Этот визуальный элемент добавляется в сетку или панель при событии Drag-Enter и удаляется при событии Drag-Leave.
  4. Когда он находится под мышью, вы получите событие перетаскивания, поскольку нарисованный элемент фактически украдет операцию перетаскивания.

Решение: Убедитесь, что IsEnabled=false для элемента, который вы рисуете под мышью.
Таким образом, он не будет захватывать вас операции перетаскивания и вы не получите эффект мерцания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...