I seem to be having a bit of an issue. I have a form on which there is a treeview. In this treeview, there are "folders" and "items". I am allowing the user to move nodes/change hierarchy for both folders and items.
I am attempting to change the mouse cursor when a drag and drop operation is in effect, however that simply does not seem to be working. I have changed all of the necessary values, and the mouse cursor during the different events, but to no avail.
Is there something missing from the code below that would prevent the proper behaviour? Basically, the cursor displayed is always the default drag and drop cursor (move, copy, etc)... Note that i have also enabled HotTracking on the treeview to enable GiveFeedback and it fires/hits the breakpoint.
[EDIT] -- Thanks to Hans for the solution. Basically, the DoDragDrop call must be targeted at the control you want by using its FQN. It doesn't matter if your source control is the one that fires the ItemDrag event, you must explicitly specify it. See code updated below.
#region Drag and Drop Methods and Event Handlers
/// <summary>
/// Performs the necessary actions when the user drags and drops a node around the treeview.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tv_Terms_DragDrop(object sender, DragEventArgs e)
{
// Retrieve the client coordinates of the drop location.
Point targetPoint = this.tv_Terms.PointToClient(new Point(e.X, e.Y));
// Retrieve the node at the drop location.
TreeNode targetNode = this.tv_Terms.GetNodeAt(targetPoint);
// confirm that the target node isn't null
// (for example if you drag outside the control)
if (targetNode != null)
{
// Retrieve the node that was dragged.
TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
TreeNode draggedParentNode = draggedNode.Parent;
//PERFORM DB OPERATIONS HERE>>
// Expand the node at the location
// to show the dropped node.
targetNode.Expand();
}
}
/// <summary>
/// Adds the necessary effect when dragging.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tv_Terms_ItemDrag(object sender, ItemDragEventArgs e)
{
this.tv_Terms.DoDragDrop(e.Item, DragDropEffects.Move);
}
/// <summary>
/// Adds the necessary effect when dragging.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tv_Terms_DragEnter(object sender, DragEventArgs e)
{
if(e.Data.GetDataPresent(typeof(TreeNode)) == true)
e.Effect = DragDropEffects.Move;
}
/// <summary>
/// Selects the appropriate node when the user is dragging an item.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tv_Terms_DragOver(object sender, DragEventArgs e)
{
//THIS METHOD AUTO-SCROLLS THE TREEVIEW IF YOU REACH THE EDGES...
this.tv_Terms.Scroll();
TreeNode node = this.tv_Terms.GetNodeAt(this.tv_Terms.PointToClient(new Point(e.X, e.Y)));
if (node != null)
{
NodeInfo info = node.Tag as NodeInfo;
if (!info.IsContainer)
node = node.Parent;
this.tv_Terms.SelectedNode = node;
}
}
private void tv_Terms_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
//I DON'T CARE WHAT TYPE OF DRAG IT IS, ALWAYS USE THE CUSTOM CURSOR.
e.UseDefaultCursors = false;
Cursor.Current = lastcursor;
}
//I SET/CACHE THE MOUSE CURSOR HERE
private void tv_Terms_MouseDown(object sender, MouseEventArgs e)
{
TreeNode node = this.tv_Terms.GetNodeAt(e.X, e.Y);
if (node != null)
{
//THIS METHOD CREATES THE CUSTOM CURSOR.
Bitmap curs = Helpers.CreateNodeCursorIcon(this.imageList1.Images[node.ImageIndex], node.Text);
this.lastcursor = new Cursor(curs.GetHicon());
//I CONFIRM THE PROPER CURSOR BY PLACING THE IMAGE IN A P.B.
this.pictureBox1.Image = curs;
Cursor.Current = lastcursor;
}
}
#endregion
DoDragDrop(e.Item, DragDropEffects.Move);
This is a subtle bug in your tv_Terms_ItemDrag() method, it uses the form's DoDragDrop() method. That matters in your case, the GiveFeedback event is fired on the drag source, not the drop target. In other words, your GiveFeedback event never fires. Easy to see with the debugger btw, simply set a breakpoint on the event handler to see it never runs. Fix:
private void tv_Terms_ItemDrag(object sender, ItemDragEventArgs e)
{
tv_Terms.DoDragDrop(e.Item, DragDropEffects.Move);
}
This method is preferably also the one where you want to create the cursor. And you should be more discriminate in the DragEnter event handler so it doesn't allow dropping everything, use e.Data.GetDataPresent(typeof(TreeNode)) to verify. And remove the cursor manipulations in DragOver.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With