узел treeview выделен, даже если я не щелкнул правой кнопкой мыши по узлу

Я работаю над winform, и в моем пользовательском интерфейсе есть древовидное представление, я обнаружил, что treenode будет выделен, даже если я не щелкнул узел правой кнопкой мыши (например, Node1 будет выделен, когда я нажму на следующую позицию), но мне действительно не нравится такое поведение, потому что я хочу показать другое контекстное меню, когда я не нажимал на treenode

+ RootNode

  |_ Node1                [ Right Click Here, Node1 will be highlighted]
  |
  |_ Node2                [ Right Click Here, Node2 will be highlighted]

person Carlos Liu    schedule 02.12.2010    source источник
comment
Я не совсем уверен, понял ли я ваш вопрос. Вы имеете в виду, что если вы щелкнете в пустом месте справа от узла, узел останется выделенным, пока вы удерживаете правую кнопку мыши?   -  person Cody Gray    schedule 02.12.2010
comment
Да, ты прав! Я не хочу, чтобы узел выделялся, когда я не нажимал на узел   -  person Carlos Liu    schedule 03.12.2010


Ответы (4)


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

Это можно сделать, обработав MouseDown событие элемента управления TreeView и установка SelectedNode свойство на null, если мышь была нажата над местом, которое не содержит узла. Например, вы можете использовать следующий код:

private void myTreeView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
    if (myTreeView.HitTest(e.Location).Node == null)
    {
        myTreeView.SelectedNode = null;
    }
}

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


РЕДАКТИРОВАТЬ: Как видно из моего комментария к вопросу, мне все еще крайне неясно, чего вы здесь пытаетесь достичь. Если вы действительно заинтересованы в предотвращении временного выделения узла, когда вы удерживаете правую кнопку мыши в пустом пространстве сбоку от узла, все становится немного сложнее.

Я рассматривал эту проблему раньше, и сложность заключается в том, что сообщения окна не принимаются, пока кнопка мыши удерживается нажатой, по крайней мере, до тех пор, пока мышь не будет перемещена (в этом случае узел все равно больше не выбирается) . Такое поведение, очевидно, продиктовано операционной системой, и его нелегко переопределить с помощью стандартных событий, предоставляемых .NET. Вы можете попытаться отменить щелчок правой кнопки в событии MouseDown в течение всего дня, но узел выбирается Windows до того, как это событие когда-либо возникнет в вашем элементе управления (помните, что предоставляемые .NET элементы управления, такие как TreeView и ListView, являются просто обертки вокруг тех же элементов управления, предоставляемых Windows API, который, по-видимому, сам реализует это поведение «select-node-while-right-button-hold-down»).

Однако то, что работает, переопределяет _ 11_ в производном TreeView элементе управления и обработка _ 13_ сообщение. Но обратите внимание, что даже установка свойства SelectedNode на null здесь не работает, потому что это не обрабатывается до тех пор, пока после Windows автоматически не выберет узел в ответ на щелчок правой кнопкой мыши - независимо от того, что вы делаете. , вы должны запретить базовому TreeView элементу управления получать WM_RBUTTONDOWN сообщение. Итак, у вас есть несколько вариантов, как с этим справиться:

  1. Вы можете просто отменить сообщение, появляющееся при щелчке правой кнопкой мыши, преждевременно выполнив экстренное спасение с помощью оператора return. Конечно, это означает, что вы не сможете обработать это событие в своем MouseDown обработчике, потому что на самом деле оно никогда не передается в элемент управления! Так что, если вы хотите показать всплывающее контекстное меню, это, вероятно, не сработает для вас.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                return;
            }
            base.WndProc(ref m);
        }   
    }
    
  2. Вы можете отобразить свое контекстное меню в переопределенном методе WndProc как ответ на сообщение WM_RBUTTONDOWN, а затем return из метода, не позволяя базовому классу обрабатывать сообщение. Это делает то же самое, что и первое решение (предотвращает то, что событие щелчка правой кнопкой мыши вызывает выделение узла), но позволяет отображать контекстное меню (или делать что-либо еще, что вы хотите) всякий раз, когда щелчок правой кнопкой мыши имеет место. Конечно, это означает, что весь соответствующий код должен содержаться в вашем подклассе элемента управления TreeView, а не обрабатываться в коде пользовательского интерфейса вашей формы, что может или не может быть удобно для вас.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                //Create and show a context menu
                var myContextMenu = new ContextMenuStrip();
                myContextMenu.Items.Add("First Item");
                myContextMenu.Items.Add("Second Item");
                return;
            }
            base.WndProc(ref m);
        }   
    }
    
  3. Вы можете инициировать свое собственное RightMouseClick событие из ваш собственный TreeView класс в качестве ответа на сообщение WM_RBUTTONDOWN, которое вы затем можете обрабатывать по своему усмотрению из кода пользовательского интерфейса вашей формы. Не передавая сообщение WM_RBUTTONDOWN базовому классу управления TreeView, это позволяет достичь той же цели, что и предыдущие два предложения, но позволяет обрабатывать событие щелчка правой кнопкой мыши в коде пользовательского интерфейса вашей формы вместо того, чтобы помещать всю свою логику в WndProc подкласса элемента управления.

    public class NewTreeView : System.Windows.Forms.TreeView
    {
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_RBUTTONDOWN = 0x204;
            if (m.Msg == WM_RBUTTONDOWN)
            {
                //Raise your custom event
                OnRightMouseClick(new EventArgs());
                return;
            }
            base.WndProc(ref m);
        }   
    }
    
person Cody Gray    schedule 02.12.2010
comment
+1: для теста попадания, но тест попадания по-прежнему будет показывать узел, вы тестировали свое решение? - person TalentTuner; 02.12.2010
comment
@Saurabh: Да, протестировано и работает нормально. Понятия не имею, о чем вы говорите. Я не использую HitTest для отмены выбора узла, я определяю, над каким узлом была нажата мышь, и, если он не был нажат над узлом, устанавливаю для свойства SelectedNode значение null, что действительно вызывает узел, который нужно отменить. Если не показать узел, вы имеете в виду, что он не удаляет узел из TreeView, и в этом случае нет, но это не то, о чем просят. - person Cody Gray; 02.12.2010
comment
@Code grey: добавлено еще одно решение, основанное на Hittesting - person TalentTuner; 02.12.2010
comment
Я тоже пробовал это, но узел подсвечивался, пока я не отпустил правый щелчок. - person SpeksETC; 02.12.2010
comment
Когда я сначала прокомментировал вопрос, мне было очень неясно, о чем именно спрашивали. Мое прочтение комментария спрашивающего на вопрос Кевина Винхолда, казалось, наводило на мысль, что мое первое решение было ответом. Последние несколько комментариев говорят об обратном, поэтому я обновил свой ответ некоторыми другими идеями. - person Cody Gray; 02.12.2010
comment
@Cody Gray: если вы действительно заинтересованы в том, чтобы узел не выделялся временно, пока вы удерживаете правую кнопку мыши в пустом пространстве сбоку от узла, все становится немного сложнее. ---- это то, что я хочу - person Carlos Liu; 03.12.2010

Я нашел другой способ предотвратить выделение узла, когда пользователь не нажимает на узел, и я устанавливаю только BackColor и ForeColor для каждого узла при добавлении его в дерево.

newNode.BackColor = treeview1.BackColor;
newNode.ForeColor = treeview1.ForeColor;
treeview1.Nodes.Add(newNode);

Затем в событии MouseDown установите свойство SelectedNode следующим образом

 private void treeView1_MouseDown(object sender, MouseEventArgs e)
 {
        TreeNode Node = treeView1.GetNodeAt(e.Location);
        if (Node != null && Node.Bounds.Contains(e.Location))
            treeView1.SelectedNode = Node;
        else
            treeView1.SelectedNode = null;
 } 
person Carlos Liu    schedule 03.12.2010
comment
Я полагаю, это работает, за исключением того, что вы все еще видите прямоугольник выбора на узле, пока удерживаете кнопку мыши. Он не заполняет прямоугольник выделения (потому что вы изменили BackColor), но пунктирный контур все еще там. Но я полагаю, что если вы не такой одержимый перфекционист, как я, это сработает. :-) - person Cody Gray; 03.12.2010
comment
@Code Gray: я не видел пунктирного контура, если не нажимал на узел - person Carlos Liu; 06.12.2010

попробуй это

  void treeView1_MouseDown(object sender, MouseEventArgs e)
    {


        TreeViewHitTestInfo h = treeView1.HitTest(e.Location);

        if (h.Location != TreeViewHitTestLocations.Label && h.Location!= TreeViewHitTestLocations.None )
        {
            treeView1.SelectedNode = null;
        }
    }
person TalentTuner    schedule 02.12.2010
comment
Я понимаю, о чем вы сейчас говорите, но если предположить, что спрашивающий хочет, чтобы узел не отображался выбранным при нажатой правой кнопке мыши, это тоже не сработает. - person Cody Gray; 02.12.2010

Если я правильно вас понял, вы не хотите, чтобы узел выбирался, если пользователь нажимает на пустое пространство в TreeView. Этого можно добиться, обработав событие MouseDown для дерева и установив для свойства SelectedNode дерева значение TreeView.GetNodeAt (e.Location).

person Kevin Wienhold    schedule 02.12.2010
comment
Да, я не хочу, чтобы какой-либо узел выделялся, когда пользователь нажимает на пустое пространство в древовидном представлении, и я пробовал ваш код, но он не работает - person Carlos Liu; 02.12.2010
comment
@Carlos_Liu: Я удивлен, что у вас это не работает, я просто попробовал сам, и, похоже, все работает нормально. - person Kevin Wienhold; 02.12.2010
comment
Если подумать, если для FullRowSelect установлено значение true, GetNodeAt вернет узел, даже если курсор мыши находится рядом с текстом. Может быть, это может объяснить вашу проблему? - person Kevin Wienhold; 02.12.2010
comment
узел не будет выделен, когда вы щелкните правой кнопкой мыши пустое место справа от узла на вашем компьютере? - person Carlos Liu; 03.12.2010