none
WPF: Компонент захватывает и не отпускет мышь (событие MouseUp). Как заставить освободить? RRS feed

  • Вопрос

  • Доброго дня!

    Такой вопрос, над которым уже долго бьюсь. Имеется TreeView, ListView и кнопки. На элементы TreeViewItem, ListViewItem, как и на сами   TreeView, ListView повешены события - MouseDown, MouseUp, MouseMove в разных вариантах (т.е. имеется и PreviewMouseMove, и MouseLeftButtonUp и проч.)

    Вся эта песня призвана заменить стандартный Drag&Drop - при перетаскивании объекта рисуется маленькое окошко с названием этого объекта. Окошко типа Window, отображается как Show (а не ShowDialog), Focusable = false. События не перехватывает и не обрабатывает.

    И вот возникает такая беда - когда я несу элемент мышкой с   TreeView на ListView и отпускаю мышь - событие MouseUp не вызывается. Аналогично,  с  TreeView или  ListView тащу на кнопку - опять не вызывается. А событие MouseMove, что интересно, описанное ровно так же, как и MouseUp/PreviewMouseUp - работает. Причём работает и для формы, и для  конкретных контролов.

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

    Логика вроде подсказывает, что виновато окошко с именем объекта. Но PreviewMouseMove работает на главной форме и с этим окошком (хотя главное в это время неактивно), а  PreviewMouseUp - нет. И обработчик  PreviewMouseUp в малом окошке также не вызывается.  

    Что может препятствовать событию отпускания мыши? Mouse.Capture(null) вызывал - не помогает.

    Заранее большое спасибо! 

    • Изменено SvarogichRed 2 ноября 2012 г. 12:15
    2 ноября 2012 г. 10:49

Ответы

  • В общем, я решил проблему так.

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

    Пришлось создать и запустить DispatcherTimer с периодом 25 миллисекунд, который смотрит на проперти Mouse.LeftButton и соответственно реагирует.

    Интересно, что System.Timers.Timer, который я сначала пытался использовать для проверки кнопок мыши, не годится. Выяснилось, что он работает в параллельном потоке и обращение в его обработчике к Mouse.LeftButton вызывает exception .

    Помечу это как ответ, т.к. задача всё же решена.

    • Помечено в качестве ответа SvarogichRed 6 ноября 2012 г. 12:17
    6 ноября 2012 г. 12:17

Все ответы

  • А по какой причине вы решили реализовывать перетаскивание таким хитромудрым способом? Ведь в WPF есть очень мощная система перетаскивания. Читайте!

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    2 ноября 2012 г. 14:00
    Отвечающий
  • Событие DragOver работает медленно, вызывается реже, чем MouseMove. Окошко с именем объекта отстаёт от мыши. Прописывать перерисовку окошка по новым координатам приходится на DragOver каждого объекта, над которым оно едет (в т.ч. приходится обрабатывать DragOver в самом окошке и менять координаты оттуда), в то время как PreviewMouseMove глобально для всей формы.

    Метод DoDragDrop тоже притормаживает, в режим перетаскивания приложение переходит не мгновенно.

    Ещё один неприятный момент, объяснения которому пока не нашёл. На событии MouseMove при нажатой мыши я вызываю Show() окошка с именем объекта, а затем DoDragDrop. Так вот, при первом выполнении это окошко не отображается! А при втором и следующих оно уже видно на экране. Если метод DoDragDrop после Show вообще отключить, то окно видно и при первой попытке перетаскивания. Но тогда, конечно, не работают связанные с  Drag&Drop события.  Проверял - окошко нигде не гасится, до самого отжатия мыши оно считается Visible. Но на экране его нет, если после Show стоит  DoDragDrop. Мистика.  

    Разумеется, если других путей нет, придётся использовать Drag&Drop. Его событие  Drop пашет, проверял. Но всё же хотелось бы узнать, почему не работает MouseUp...

    P.S. Я прочёл всю предложенную  Вами статью, но не нашёл там способа изменить курсор мыши на имя объекта. То есть придётся всё-таки оставить окошко.




    • Изменено SvarogichRed 6 ноября 2012 г. 5:02
    6 ноября 2012 г. 3:55
  • В общем, я решил проблему так.

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

    Пришлось создать и запустить DispatcherTimer с периодом 25 миллисекунд, который смотрит на проперти Mouse.LeftButton и соответственно реагирует.

    Интересно, что System.Timers.Timer, который я сначала пытался использовать для проверки кнопок мыши, не годится. Выяснилось, что он работает в параллельном потоке и обращение в его обработчике к Mouse.LeftButton вызывает exception .

    Помечу это как ответ, т.к. задача всё же решена.

    • Помечено в качестве ответа SvarogichRed 6 ноября 2012 г. 12:17
    6 ноября 2012 г. 12:17