Suchen Sie den Knoten, auf den Sie im Kontextmenü geklickt haben

73

Wie kann ich herausfinden, auf welchem ​​Knoten in einer Baumliste das Kontextmenü aktiviert wurde? Klicken Sie beispielsweise mit der rechten Maustaste auf einen Knoten und wählen Sie eine Option aus dem Menü aus.

Ich kann die SelectedNodeEigenschaft von TreeViews nicht verwenden, da der Knoten nur mit der rechten Maustaste angeklickt und nicht ausgewählt wurde.

Sam
quelle

Antworten:

93

Sie können der TreeView ein Mausklickereignis hinzufügen und dann mit GetNodeAt den richtigen Knoten auswählen, wobei die von MouseEventArgs bereitgestellten Mauskoordinaten angegeben werden.

void treeView1MouseUp(object sender, MouseEventArgs e)
{
    if(e.Button == MouseButtons.Right)
    {
        // Select the clicked node
        treeView1.SelectedNode = treeView1.GetNodeAt(e.X, e.Y);

        if(treeView1.SelectedNode != null)
        {
            myContextMenuStrip.Show(treeView1, e.Location);
        }
    }
}
Jonesinator
quelle
7
Vielen Dank, ich habe eine kleine Ergänzung zur Lösung: Sie können auch das Ereignis "_NodeMouseClick" verwenden, das Ihnen ein "TreeNodeMouseClickEventArgs e" gibt. In diesem Fall können Sie einfach den e.Node verwenden und müssen sich nicht um die Überprüfung kümmern ob der Knoten null ist oder nicht.
SDM
Ich habe das gewünschte Ergebnis mit dem MouseDown-Ereignis anstelle von MouseUp erhalten.
Javier
21

Hier ist meine Lösung. Fügen Sie diese Zeile in das NodeMouseClick-Ereignis der TreeView ein:

 ((TreeView)sender).SelectedNode = e.Node;
deej
quelle
Die Maus-Ereignis-Argumente haben keine .Node
CAD-Kerl
2
Ja, aber TreeNodeMouseClickEventArgs (die an das NodeMouseClick- Ereignis übergeben werden) tun dies. Meine Lösung funktioniert also und ist nicht überkompliziert wie einige andere Lösungen
DJ
12

Ich finde das Standardverhalten bei der Auswahl der Windows-Baumansicht ziemlich ärgerlich. Wenn Sie beispielsweise den Explorer verwenden und mit der rechten Maustaste auf einen Knoten klicken und auf Eigenschaften klicken, wird der Knoten hervorgehoben und der Eigenschaftendialog für den Knoten angezeigt, auf den Sie geklickt haben. Wenn Sie jedoch aus dem Dialogfeld zurückkehren, war der markierte Knoten der Knoten, der zuvor ausgewählt / hervorgehoben wurde, bevor Sie mit der rechten Maustaste geklickt haben. Ich finde, dass dies Usability-Probleme verursacht, weil ich für immer verwirrt bin, ob ich auf dem richtigen Knoten gehandelt habe.

In vielen unserer GUIs ändern wir den ausgewählten Baumknoten mit einem Rechtsklick, damit keine Verwirrung entsteht. Dies ist möglicherweise nicht dasselbe wie eine Standard-iwndos-App wie Explorer (und ich tendiere dazu, unser GUI-Verhalten aus Usabiltiy-Gründen stark nach Standard-Fenster-Apps zu modellieren). Ich glaube, dass dieser eine Ausnahmefall zu weitaus benutzerfreundlicheren Bäumen führt.

Hier ist ein Code, der die Auswahl beim Klicken mit der rechten Maustaste ändert:

  private void tree_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  {
     // only need to change selected note during right-click - otherwise tree does
     // fine by itself
     if ( e.Button == MouseButtons.Right )
     {         
        Point pt = new Point( e.X, e.Y );
        tree.PointToClient( pt );

        TreeNode Node = tree.GetNodeAt( pt );
        if ( Node != null )
        {
           if ( Node.Bounds.Contains( pt ) )
           {
              tree.SelectedNode = Node;
              ResetContextMenu();
              contextMenuTree.Show( tree, pt );
           }
        }
     }
  }
Marcus Erickson
quelle
Dies ist die beste Lösung für mich, da sie tatsächlich den Knoten auswählt, auf den Sie geklickt haben.
CAD Kerl
8

Wiederbelebung dieser Frage, weil ich dies für eine viel bessere Lösung halte. Ich benutze NodeMouseClickstattdessen das Ereignis.

void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if( e.Button == MouseButtons.Right )
    {
        tree.SelectedNode = e.Node;
    }
}
Beta Carotin
quelle
Das gefällt mir auch viel besser.
Joey Novak
3

Dies ist eine sehr alte Frage, aber ich fand sie trotzdem nützlich. Ich verwende eine Kombination einiger der oben genannten Antworten, da ich nicht möchte, dass der mit der rechten Maustaste angeklickte Knoten zum ausgewählten Knoten wird. Wenn ich den Stammknoten ausgewählt habe und eines seiner untergeordneten Knoten löschen möchte, möchte ich nicht, dass das untergeordnete Element ausgewählt wird, wenn ich es lösche (ich arbeite auch an dem ausgewählten Knoten, den ich nicht auf der rechten Seite ausführen möchte). klicken). Hier ist mein Beitrag:

// Global Private Variable to hold right-clicked Node
private TreeNode _currentNode = new TreeNode();

// Set Global Variable to the Node that was right-clicked
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
        _currentNode = e.Node;
}

// Do something when the Menu Item is clicked using the _currentNode
private void toolStripMenuItem_Clicked(object sender, EventArgs e)
{
    if (_currentNode != null)
        MessageBox.Show(_currentNode.Text);
}
George
quelle
2

Ähnlich wie bei Marcus 'Antwort war dies die Lösung, die für mich funktioniert hat:

private void treeView_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        treeView.SelectedNode = treeView.GetNodeAt(e.Location);
    }
}

Sie müssen das Kontextmenü nicht selbst anzeigen, wenn Sie es wie folgt auf jeden einzelnen Knoten einstellen:

TreeNode node = new TreeNode();
node.ContextMenuStrip = contextMenu;

Dann öffnet die TreeView.SelectedNode-Eigenschaft im Eröffnungsereignis des ContextMenu den richtigen Knoten.

Trevor Elliott
quelle
0

Wenn Sie möchten, dass das Kontextmenü von dem ausgewählten Element abhängt, bewegen Sie sich am besten, indem Sie Jonesinators Code verwenden, um das angeklickte Element auszuwählen. Der Inhalt Ihres Kontextmenüs kann dann vom ausgewählten Element abhängen.

Die Auswahl des Elements zuerst und nicht nur die Verwendung für das Kontextmenü bietet einige Vorteile. Das erste ist, dass der Benutzer eine visuelle Anzeige hat, auf welche er geklickt hat und mit welchem ​​Element das Menü verknüpft ist. Das zweite ist, dass es auf diese Weise viel einfacher ist, mit anderen Methoden zum Aufrufen des Kontextmenüs kompatibel zu bleiben (z. B. Tastaturkürzel).

ICR
quelle
0

Hier ist, wie ich es mache.

private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
        e.Node.TreeView.SelectedNode = e.Node;
}
Ricky Manwell
quelle
0

Eine andere Option, mit der Sie ausgeführt werden können, ist eine globale Variable mit dem ausgewählten Knoten. Sie müssten nur die verwenden TreeNodeMouseClickEventArgs.

public void treeNode_Click(object sender, TreeNodeMouseClickEventArgs e)
{
    _globalVariable = e.Node;
}

Jetzt haben Sie Zugriff auf diesen Knoten und seine Eigenschaften.

sparkyShorts
quelle
0

Ich möchte eine Alternative zur Verwendung der Klickereignisse unter Verwendung des Ereignisses des Kontextmenüs vorschlagen Opened:

private void Handle_ContextMenu_Opened(object sender, EventArgs e)
{
    TreeViewHitTestInfo info = treeview.HitTest(treeview.PointToClient(Cursor.Position));
    TreeNode contextNode;

    // was there a node where the context menu was opened?
    if (info != null && info.Node != null)
    {
        contextNode = info.Node;
    }

    // Set the enabled states of the context menu elements
    menuEdit.Enabled = contextNode != null;
    menuDelete.Enabled = contextNode != null;
}

Dies hat die folgenden Vorteile, die ich sehen kann:

  • Der ausgewählte Knoten wird nicht geändert
  • Zum Speichern der Zielknoteninstanz ist kein separater Ereignishandler erforderlich
  • Kann Menüelemente deaktivieren, wenn der Benutzer mit der rechten Maustaste auf den leeren Bereich in der Baumansicht klickt

Hinweis: Wenn Sie befürchten, dass der Benutzer die Maus zum Zeitpunkt des Öffnens des Menüs bereits bewegt hat, können Sie Openingstattdessen das Ereignis verwenden.

AeonOfTime
quelle