Проблема с запуском контекстного меню у объекта 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 я не копал, так что пожалуй это не плохая тема для отдельного вопроса
Комментариев нет:
Отправить комментарий