Страницы

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

вторник, 10 декабря 2019 г.

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

#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 я не копал, так что пожалуй это не плохая тема для отдельного вопроса.

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

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