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

Context menu question
Don Miller
Wow !
Thanks for the sample
I think it would do for now.
Thanks
Avi
Majka
Thanks
I have ~ 10 types of nodes in the tree.
Avi
enaim254
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
supergatito123
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.
mmenasches
Anonymous233e
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");
}
Smafuda
No, this is not correct. If you store the ContextMenu's in the Tag property for example, you only store a reference!
nery_jose
Nick Jovanelly
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
Duncan Faulkner
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 ) );
}
}
A. S.
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.