#c_sharp #winforms
Проблема с запуском контекстного меню у объекта 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 = "Расширенный поиск предусмотрен только по пересечению видов"; } }
Ответы
Ответ 1
У 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 я не копал, так что пожалуй это не плохая тема для отдельного вопроса.
Комментариев нет:
Отправить комментарий