I am making a winforms app where the user can add nodes to a tree view by right clicking on a node or the background. If the user clicks a node, the new node should become the child of that node, otherwise it will be added to the root of the tree view.
My problem is that there is no function to check if the background is clicked. Below is what I have so far. Unfortunately, if a node is clicked right now then the child will be added to both the root and the parent node.
private void treeView_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right) addChild(null);
}
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Right) addChild(e.Node);
}
private void addChild(TreeNode parent)
{
TreeNode node = new TreeNode("new node");
// If didn't click on a node, add to root, otherwise add to parent
if (parent == null) treeView.Nodes.Add(node);
else parent.Nodes.Add(node)
node.Parent.Expand();
}
move your code from MouseClick to MouseUp (when user releases mouse button). Then check by mouse coordinates is there node on that location.
Take a look at this code:
private void treeView1_MouseUp(object sender, MouseEventArgs e)
{
var clickedNode = treeView1.GetNodeAt(e.X, e.Y);
if (clickedNode == null)
{
//clicked on background
addChild(null);
}
else
{
//clicked on node
addChild(clickedNode);
}
}
Related
I have the DragAndDrop Event such as below for both my treeviews (treeV and treeV_IgnoreD):
private void treeV_IgnoredDragDropEvent(object sender, DragEventArgs e)
{
// Retrieve the client coordinates of the drop location.
Point targetPoint = treeV_Ignored.PointToClient(new Point(e.X, e.Y));
// Retrieve the node at the drop location.
TreeNode targetNode = treeV.GetNodeAt(targetPoint);
// Retrieve the node that was dragged.
TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
// Confirm that the node at the drop location is not
// the dragged node and that target node isn't null
// (for example if you drag outside the control)
if (!draggedNode.Equals(targetNode) && targetNode != null)
{
// Remove the node from its current
// location and add it to the node at the drop location.
draggedNode.Remove();
targetNode.Nodes.Add(draggedNode);
// Expand the node at the location
// to show the dropped node.
targetNode.Expand();
}
}
private void treeV_Ignored_ItemDrag(object sender, ItemDragEventArgs e)
{
DoDragDrop(e.Item, DragDropEffects.Move);
MessageBox.Show("ola");
}
private void treeV_Ignored_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
These treeviews are populated from a Oracle dataset, and represent the same data.
I want to be able to drag an item from "treeV", and drop it within "treeV_Ignored".
How can I achieve that behaviour?
your requirement is full fill with this link
kindly look into.
Further more , you have to understand first, here SplitContainer is used for drag and drop purpose thorough which we can add our treeview to this control, so we easily drag any node to another tree. If you have any issue let me know
I need to do drag and drop using treeview in c#.For that i heard 3 events are the most common
1.itemDrag
2.DragDrop and 3.DragEnter.
whereas here itemDrag event is firing for me while dragging from a treeview ,but rest both the events are not firing for me.Tried many solutions and now came here for an solution
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
string[] strItem = e.Item.ToString().Split(':');
DoDragDrop(strItem[1], DragDropEffects.Copy | DragDropEffects.Move); }
the above method fires ,
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
the bove dragEnter event is not firing ,similarly the dragDrop event is also not firing.Why it's so??
Am dragging from the treeview and need to paste in PowerPoint or Word. (ie) treeview is something like an AddIn for Office Tools.
Regards,
Arshad
Allow Drop AND..
Ok, assuming you have all of your events being declared/created in the Form_Load... e.i.
:
tlAssemblies.DragDrop +=tlAssemblies_DragDrop;
tlAssemblies.MouseDown +=tlAssemblies_MouseDown;
tlAssemblies.MouseMove +=tlAssemblies_MouseMove;
tlAssemblies.DragEnter +=tlAssemblies_DragEnter;
tlAssemblies.DragOver += tlAssemblies_DragOver;
The drag Event is for when you fire the drag event inside your treeView which is why it is working. The dragEnter is when you enter the boundaries of a different* control.
i.e you want to drag from treeview 1 into treeview2.
If you are not trying to drag the item into a different control dragEnter is wrong.
Here is a drag drop event sample :
private void tlAssemblies_DragDrop(object sender, DragEventArgs e)
{
if (sender == null)
return;
Point p = tlAssemblies.PointToClient(new Point(e.X, e.Y));
TreeListNode dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
TreeListNode targetNode = tlAssemblies.CalcHitInfo(p).Node;
if (targetNode == null)
{
return;
}
}
Not sure if it is possible but you may want to change the dragEnter code you have and simply use it in the drag event i.e.
e.Effect = DragDropEffects.Move;
If you are not leaving the same control you are dragging both to and fro, might as well show the drag movement.
Another thing you could do is on the treeView_MouseMove Event.
private void tlAssemblies_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && downHitInfo != null)
{
Size dragSize = SystemInformation.DragSize;
Rectangle dragRect = new Rectangle(new Point(downHitInfo.HitPoint.X - dragSize.Width / 2,
downHitInfo.HitPoint.Y - dragSize.Height / 2), dragSize);
if (!dragRect.Contains(new Point(e.X, e.Y)))
{
DataRow row = viewProduct.GetDataRow(downHitInfo.RowHandle);
if(row != null)
tlAssemblies.DoDragDrop(row, DragDropEffects.Move);
//viewProduct.GridControl.DoDragDrop(row, DragDropEffects.All);
downHitInfo = null;
DevExpress.Utils.DXMouseEventArgs.GetMouseArgs(e).Handled = true;
}
}
}
From your provided code, I cannot see that you have implemented the DragDrop event nor have set the AllowDrop property on the controls involved, which is needed along with the two other events in order to perform a drag and drop.
Here is sample snatched directly from MSDN, which uses two treeviews to move nodes in between. Add a couple of treeviews, add some root and child nodes, and wire up these events. Remember the AllowDrop property.
I have added a couple of Debug.WriteLine() to help with the debugging while testing this. Can be hard to do with breakpoints ;-)
NOTE: For brewity I have not supplied the event wiring code, nor the code for creating sample nodes. If needed this can be found in the referenced article. Otherwise add those using the property window.
Sample code:
private void treeView_ItemDrag(object sender, ItemDragEventArgs e)
{
Debug.WriteLine("ItemDrag fired!");
DoDragDrop(e.Item, DragDropEffects.Move);
}
private void treeView_DragEnter(object sender, DragEventArgs e)
{
Debug.WriteLine("TreeView DragEnter fired!");
e.Effect = DragDropEffects.Move;
}
private void treeView_DragDrop(object sender, DragEventArgs e)
{
Debug.WriteLine("TreeView DragDrop fired!");
TreeNode NewNode;
if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode", false))
{
Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));
TreeNode DestinationNode = ((TreeView)sender).GetNodeAt(pt);
NewNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
if (DestinationNode.TreeView != NewNode.TreeView)
{
DestinationNode.Nodes.Add((TreeNode)NewNode.Clone());
DestinationNode.Expand();
//Remove Original Node
NewNode.Remove();
}
}
}
I make windows form application. I have on form TreeView, I add few nodes and add ContextMenuStrip.
var menu = new ContextMenuStrip();
menu.Items.Add("Some text", new Bitmap(1, 1), new EventHandler(function_name));
var treeView = new TreeView(..);
treeView.ContextMenuStrip = menu;
treeView.Nodes.Add(new TreeNode()
{
...
Tag = someObject
});
My problems is how can I check in function function_name on which treeNode was clicked and chosen option from ContextMenuStrip
edit
function_name sygnature
public void pokaz_DoubleClick(object sender, EventArgs e)
{
}
You can handle the TreeNodeMouseClick event. In your TreeNodeMouseClickEventHandler you will have access to a TreeNodeMouseClickEventArgs argument. This argument contains a number of properties you can use to check which mouse button was clicked on which node. For example.
private TreeNode rightClickeNode;
void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
rightClickedNode = e.Node;
}
}
You can then access rightClickedNode from your function_name.
what is the signature of the function_name method?
generally you can check the content of the sender parameter but it could happen it is the TreeView and not the TreeNode, if so you can check the properties of the e parameter.
Another way is that at every mouse down you make sure you select the node under the mouse in the TreeView so when function_name executes you get your node taking treeview.SelectedNode
You can make the node selected right before the Context Menu is shown and then you just need to check the SelectedNode property. Something like this:
private void treeView_MouseDown(object sender, MouseEventArgs e)
{
//See what node is at the location that was just clicked
var clickedNode = treeView.GetNodeAt(e.Location);
//Make that node the selected node
treeView.SelectedNode = clickedNode;
}
private void function_name(object sender, EventArgs e)
{
var currentNode = treeView.SelectedNode;
//Do something with currentNode
}
I m working on windows project and using c#. I want to catch treeview selected node which i click that by right click.
I'm writing tvlocation.SelectedNode.Index
but it return only Root Node's index.
Thanks for your helps...
If you are looking to identify the node that was clicked on, then handle the NodeMouseClick event, as follows:
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
MessageBox.Show(string.Format("Node clicked: {0}", e.Node.Text));
}
}
You could select the node programatically here, if you need that too.
How can I find out which node in a tree list the context menu has been activated? For instance right-clicking a node and selecting an option from the menu.
I can't use the TreeViews' SelectedNode property because the node is only been right-clicked and not selected.
You can add a mouse click event to the TreeView, then select the correct node using GetNodeAt given the mouse coordinates provided by the MouseEventArgs.
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);
}
}
}
Here is my solution. Put this line into NodeMouseClick event of the TreeView:
((TreeView)sender).SelectedNode = e.Node;
I find the standard windows treeview behavior selection behavior to be quite annoying. For example, if you are using Explorer and right click on a node and hit Properties, it highlights the node and shows the properties dialog for the node you clicked on. But when you return from the dialog, the highlighted node was the node previously selected/highlighted before you did the right-click. I find this causes usability problems because I am forever being confused on whether I acted on the right node.
So in many of our GUIs, we change the selected tree node on a right-click so that there is no confusion. This may not be the same as a standard iwndos app like Explorer (and I tend to strongly model our GUI behavior after standard window apps for usabiltiy reasons), I believe that this one exception case results in far more usable trees.
Here is some code that changes the selection during the right click:
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 );
}
}
}
}
Reviving this question because I find this to be a much better solution.
I use the NodeMouseClick event instead.
void treeview_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if( e.Button == MouseButtons.Right )
{
tree.SelectedNode = e.Node;
}
}
This is a very old question, but I still found it useful. I am using a combination of some of the answers above, because I don't want the right-clicked node to become the selectedNode. If I have the root node selected and want to delete one of it's children, I don't want the child selected when I delete it (I am also doing some work on the selectedNode that I don't want to happen on a right-click). Here is my contribution:
// 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);
}
Similar to Marcus' answer, this was the solution I found worked for me:
private void treeView_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
treeView.SelectedNode = treeView.GetNodeAt(e.Location);
}
}
You need not show the context menu yourself if you set it to each individual node like so:
TreeNode node = new TreeNode();
node.ContextMenuStrip = contextMenu;
Then inside the ContextMenu's Opening event, the TreeView.SelectedNode property will reflect the correct node.
If you want the context menu to be dependent on the selected item you're best move I think is to use Jonesinator's code to select the clicked item. Your context menu content can then be dependent on the selected item.
Selecting the item first as opposed to just using it for the context menu gives a few advantages. The first is that the user has a visual indication as to which he clicked and thus which item the menu is associated with. The second is that this way it's a hell of a lot easier to keep compatible with other methods of invoking the context menu (e.g. keyboard shortcuts).
Here is how I do it.
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
e.Node.TreeView.SelectedNode = e.Node;
}
Another option you could run with is to have a global variable that has the selected node. You would just need to use the TreeNodeMouseClickEventArgs.
public void treeNode_Click(object sender, TreeNodeMouseClickEventArgs e)
{
_globalVariable = e.Node;
}
Now you have access to that node and it's properties.
I would like to propose an alternative to using the click events, using the context menu's Opened event:
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;
}
This has the following advantages that I can see:
It does not change the selected node
No separate event handler needed to store the target node instance
Can disable menu items if the user right-clicks empty space in the TreeView
Note: if you worry that the user may have already moved the mouse by the time the menu is opened, it is possible to use the Opening event instead.