Context menu question

Hello

 

Hope its the right place for this question.

 

I have a win app that contains a treeview and a main window. When ever I click a node in the tree it displays the content of the node in the main window.

I would like to add a right click menu to the tree. The problem is that the menu may change from one node to another .

What is the best way to handle this subject Is there a pattern I can use

On every right click I need to know which menu to load and to bind the items to the proper functions

 

Thanks

Avi



Answer this question

Context menu question

  • Doug Winters

    Thanks

    I have ~ 10 types of nodes in the tree.

    Avi


  • cftdanny

    One design consideration could be that there are too many nodes and hence it may not be advisable to create (by associating 1 menu with every node) too many context menu objects in memory.
  • nate-d-o-double-g

    It's somewhat design-dependant. But, you could create a ContextMenu[Strip] object for each type of node (IIRC, you have only 10 types). Each of these objects would contain one or more MenuItem or ToolStrip items that would each have an appropriate Click event handler assigned to it. As you create each TreeNode object, set the TreeNode.ContextMenu[Strip] property to the appropriate context menu object before adding the TreeNode to the TreeView. Since each MenuItem or ToolStrip item is associated with a particular type of context menu and each context menu is associated with a particular type of node, you know if that event handler is called a particular node type is selected.

    Alternatively, in the case of ContextMenu, you could handle the Popup event and dynamically populate the menu items based upon the node at the current mouse X & Y. You can do the same with ContextMenuStrip, but the event is Opening instead of Popup. The online docs for ContextMenuStrip have an example of dynamically populating the menu items.



  • m.ramos

    No.

    what still seems to be the problem is how to bind the needed functions with the selected context menu .Lets say my factory returned a contextMenu1 and it has 3 items. How do I bind this control with the functions it should use

    Avi


  • powertechit

    I can suggest one possible design to this.

    It seems that each of your treenode is supposed to represent a particular kind of information.Hence the best way to solve this is to build Custom treenodes which derive from the treenode object and add them to the treeview.You can also add properties to associate information with them.This makes the behaviour polymorphic and you can more and more types of treenodes to one treeview and depending on the type of treenode click,you can create a context menu the way you want it,with the associated information coming in from the individual treenode.

    public class TreeNodeTypeOne : TreeNode

    {

    }

     

    public class TreeNodeTypeTwo : TreeNode

    {

    //Associate information as properties

    }

    Use Client Code such as

    this.TreeView1.Add(new TreeNodeTypeTwo("typetwo");

    this.TreeView1.Add(new TreeNodeTypeTwo("typeone");

    private void treeView1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)

    {

    TreeNode node = this.treeView1.GetNodeAt(e.X, e.Y );

    if(node!=null)

    {

    //examine the node

    if(node.GetType() == typeof(TreeNodeTypeOne))

    {

    TreeNodeTypeOne typeOneNode = node as TreeNodeTypeOne;

    //Show a context menu

    }

    if(node.GetType() == typeof(TreeNodeTypeTwo))

    {

    TreeNodeTypeTwo typeTwoNode = node as TreeNodeTypeTwo;

    //Show a different context

    }

    }

    }

     

    Hope this helps


  • Autechrian

    Peter Ritchie wrote:
    It's somewhat design-dependant. But, you could create a ContextMenu[Strip] object for each type of node (IIRC, you have only 10 types). Each of these objects would contain one or more MenuItem or ToolStrip items that would each have an appropriate Click event handler assigned to it. As you create each TreeNode object, set the TreeNode.ContextMenu[Strip] property to the appropriate context menu object before adding the TreeNode to the TreeView. Since each MenuItem or ToolStrip item is associated with a particular type of context menu and each context menu is associated with a particular type of node, you know if that event handler is called a particular node type is selected.
    For example:

    private TreeNode AddTypeOneNode(String label) {
    TreeNode node = treeView.Nodes.Add(label);
    node.ContextMenu = nodeMenus[0];
    return node;
    }

    private TreeNode AddTypeOneNode(String label, TreeNode parent) {
    TreeNode node = parent.Nodes.Add(label);
    node.ContextMenu = nodeMenus[0];
    return node;
    }

    private TreeNode AddTypeTwoNode(String label) {
    TreeNode node = treeView.Nodes.Add(label);
    node.ContextMenu = nodeMenus[1];
    return node;
    }

    private TreeNode AddTypeTwoNode(String label, TreeNode parent) {
    TreeNode node = parent.Nodes.Add(label);
    node.ContextMenu = nodeMenus[1];
    return node;
    }

    ContextMenu[] nodeMenus;

    private void Form1_Load(object sender, EventArgs e) {
    nodeMenus = new ContextMenu[2];

    //create context menu for TypeOne nodes
    nodeMenus[0] = new ContextMenu();
    nodeMenus[0].MenuItems.Add(new MenuItem("Toggle Enabled", new EventHandler(Form1_TypeOneNodeToggleEnabledClick)));
    nodeMenus[0].MenuItems.Add(new MenuItem("P&roperties...", new EventHandler(Form1_TypeOneNodePropertiesClick)));
    //create context menu for TypeTwo nodes
    nodeMenus[1] = new ContextMenu();
    nodeMenus[1].MenuItems.Add(new MenuItem("Toggle Enabled", new EventHandler(Form1_TypeTwoNodeToggleEnabledClick)));
    nodeMenus[1].MenuItems.Add(new MenuItem("P&roperties...", new EventHandler(Form1_TypeTwoNodePropertiesClick)));

    // populate tree
    AddTypeOneNode("Type one a");
    TreeNode node = AddTypeTwoNode("Type two a");
    AddTypeOneNode("Type one a type one child 1", node);
    AddTypeTwoNode("Type one a type two child 1", node);
    AddTypeOneNode("Type one b");
    node = AddTypeOneNode("Type two b");
    AddTypeOneNode("Type one a type one child 1", node);
    AddTypeTwoNode("Type one a type two child 1", node);
    }

    void Form1_TypeOneNodeToggleEnabledClick(object sender, EventArgs e) {
    MessageBox.Show(this, "Type one node Toggle Enabled clicked!", "Message");
    }

    void Form1_TypeOneNodePropertiesClick(object sender, EventArgs e) {
    MessageBox.Show(this, "Type one node Properties clicked!", "Message");
    }

    void Form1_TypeTwoNodeToggleEnabledClick(object sender, EventArgs e) {
    MessageBox.Show(this, "Type two node Toggle Enabled clicked!", "Message");
    }

    void Form1_TypeTwoNodePropertiesClick(object sender, EventArgs e) {
    MessageBox.Show(this, "Type two node Properties clicked!", "Message");
    }



  • Yaron Becker

    Karthik Krishnaswami wrote:
    One design consideration could be that there are too many nodes and hence it may not be advisable to create (by associating 1 menu with every node) too many context menu objects in memory.


    No, this is not correct. If you store the ContextMenu's in the Tag property for example, you only store a reference!


  • Apopka_Pilot

    You can use the Tag property of the TreeNode object to store the context menu if you like.

    Here is a little example:

    Add Node

    TreeNode newNode = new TreeNode( "MyNode" );
    newNode.Tag = contextMenu1;
    treeView1.Nodes.Add( newNode );



    Show menu

    private void treeView1_MouseDown(object sender, MouseEventArgs e)
    {
    TreeNode node = this.treeView1.GetNodeAt(e.X, e.Y );

    if( node != null && node.Tag is ContextMenu )
    {
    ContextMenu menu = (ContextMenu)node.Tag;
    menu.Show( treeView1, new Point( e.X, e.Y ) );
    }
    }




  • brjali

    The TreeNode class has a ContextMenu and a ContextMenuStrip property. Have you tried using either of these

  • JorgeRoca

    Wow !

    Thanks for the sample

    I think it would do for now.

    Thanks

    Avi


  • Shane Bell

    Then the design I proposed would work.What you can do is to create a Factory which would return you a fully loaded context menu object depending on the type of Node.

    You can have something like-

    MenuFactory.cs

    public static ContextMenu(TreeNode node)

    {

    //Put in the logic to test for type of node and create a context menu fully with data as per the data of the node

    if(node!=null)

    {

    //examine the node

    if(node.GetType() == typeof(TreeNodeTypeOne))

    {

    TreeNodeTypeOne typeOneNode = node as TreeNodeTypeOne;

    //Create a context menu

    }

    if(node.GetType() == typeof(TreeNodeTypeTwo))

    {

    TreeNodeTypeTwo typeTwoNode = node as TreeNodeTypeTwo;

    //Create a different context

    }

    }

    Client code would be-

    private void treeView1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)

    {

    TreeNode node = this.treeView1.GetNodeAt(e.X, e.Y);

    if (node != null)

    {

    ContextMenu menu = MenuFactory.CreateContextMenu(node);

    menu.Show(treeView1, new Point(e.X, e.Y));

    }

    }

    Yes,you can use a Factory to solve your problem.


  • Context menu question