Страницы

Поиск по вопросам

вторник, 16 октября 2018 г.

c# WinForms: проблемы с вызовом конекстного меню после добавления Drag-Drop

Проблема с запуском контекстного меню у объекта TreeView на форме. После того, как пользователь левой кнопкой выделил элемент в дереве, ему нужно два раза жать на правую кнопку мыши, чтобы появилось контекстное меню. Клиента это очень раздражает.
Проблема появилась после того, как treeView на форме стал использоваться, как источник данных в процедуре перетаскивания мышью Drag-Drop, реализованными стандартными средствами MicroSoft.
В обработчик нажатия был добавлен следующий код:
private void treeView_MouseDown(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { TreeNode node = treeView.GetNodeAt(e.X, e.Y);
if (node != null) { // ... некоторые предварительные вычисления, // не влияющие на элементы формы, а меняющие Tag у node
//Проблемы появились после добавления этой стандартной функции от MicroSoft treeView.DoDragDrop(node, DragDropEffects.Copy);
//Это старый код, который должен остаться и при котором все работало treeView.SelectedNode = node; } } }
Сам Drag-Drop отрабатывается без проблем.
Если важно, то на treeView_AfterSelect реализован обработчик, заполняющий элементы формы информацией
private void treeView_AfterSelect(object sender, TreeViewEventArgs e) { TreeNode currentNode = treeView.SelectedNode; if (currentNode != null) { FillAll(currentNode); } }
Подскажите, пожалуйста как решить эту проблему без реализации собственного Drag-Drop, либо как объяснить клиенту, что это не баг в реализации DoDragDrop() MicroSoft-ом, а фича.
Детальное изучение это редкого явления показало, что для останова процедуры DoDragDrop() недостаточно просто отпустить левую кнопку мыши. Обработчик treeView_MouseUp() в случае использования стандартного DoDragDrop() на него не отзывается.
UpDate от 26.12.2016: По запросу добавляю код, обрабатывающий события процедуры DragDrop:
1) На событие DragEnter для контрола ListBox lstBxForSearch; , который является приемником DragDrop повешен следующий обработчик:
private void lstBxForSearch_DragEnter(object sender, DragEventArgs e) { // Предварительно сбрасываем флаг допустимости использования контрола lstBxForSearch, // как приемника процедуры DragDop e.Effect = DragDropEffects.None;
// Устанавливаем этот флаг, если объект, который тянем, может быть принят // контролом lstBxForSearch, то есть источником служит контрол treeView if (e.Data.GetDataPresent(typeof(TreeNode))) { TreeNode node = e.Data.GetData(typeof(TreeNode)) as TreeNode; if (node != null && node.TreeView == treeView) { //Допустимый источник e.Effect = DragDropEffects.Copy; } } }
2) На событие DragDrop для ListBox lstBxForSearch; повешен такой обработчик:
private void lstBxForSearch_DragDrop(object sender, DragEventArgs e) { //Анализируем, что принесли на мыше TreeNode node = e.Data.GetData(typeof(TreeNode)) as TreeNode; if (node == null) return; addPlantToSearchList(node); }
и соответственно
private void addPlantToSearchList(TreeNode currentNode) { PlantExtendTag tg = currentNode.Tag as PlantExtendTag; if (tg == null) return;
MyDS.PlantShort_ViewRow plantRow = tg.PlantRow;
if ((TacsonomyLeve)plantRow.LevelNum == TacsonomyLeve.Kind) { lstBxPlantsForSearch.Items.Add(new NameId(plantRow.Id, currentNode.Text)); } else { toolStripStatusLabel.Text = "Расширенный поиск предусмотрен только по пересечению видов"; } }


Ответ

У TreeView есть специальное событие TreeView.ItemDrag. Это событие срабатывает, когда после мы начинаем тянуть элемент с зажатой клавишей мыши (можно настроить какой именно клавишей). При обычном клике оно не срабатывает. Подписываемся на него, и в нем начинаем процедуру перетаскивания. Например так:
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e) { if(e.Button == MouseButtons.Left) { treeView1.DoDragDrop(e.Item, DragDropEffects.Move); } }
Теперь можно убрать вызов DoDragDrop из обработчика MouseDown и забыть про багофичу с правым кликом.

Это не единственный сюрприз от DoDragDrop. После его активации перестают обрабатываться все события мыши до его завершения. Скорее всего это связано с тем, что события мыши передаются оконному менеджеру, а не окну вашей программы, т.к. DragDrop может перетаскивать объекты между программами, а для этого нужен внешний контекст. Но глубоко в WinAPI я не копал, так что пожалуй это не плохая тема для отдельного вопроса

Комментариев нет:

Отправить комментарий