private void treeviewDragFinishingHandler(object sender, DragFinishingEventArgs e) { // we want to finish off the drag ourselves, and not have the treeview control move the nodes around. // (In fact, in a lame attempt at 'data binding', we're going to completely redraw the tree after // making all the required changes from this drag-drop.) So set the flag to indicate that. e.FinishDrag = false; // first determine the node that they will be moved to. This will depend on if we are dragging onto a node // directly, or above/below one to reorder. ElementNode newParentNode = null; // the ElementNode that the selected items will move to TreeNode expandNode = null; // if we need to expand a node once we've moved everything int index = -1; if (e.DragBetweenNodes == DragBetweenNodes.DragOnTargetNode) { newParentNode = e.TargetNode.Tag as ElementNode; expandNode = e.TargetNode; } else if (e.DragBetweenNodes == DragBetweenNodes.DragBelowTargetNode && e.TargetNode.IsExpanded) { newParentNode = e.TargetNode.Tag as ElementNode; expandNode = e.TargetNode; index = 0; } else { if (e.TargetNode.Parent == null) { newParentNode = null; // needs to go at the root level } else { newParentNode = e.TargetNode.Parent.Tag as ElementNode; } if (e.DragBetweenNodes == DragBetweenNodes.DragAboveTargetNode) { index = e.TargetNode.Index; } else { index = e.TargetNode.Index + 1; } } // Check to see if the new parent node would be 'losing' the Element (ie. becoming a // group instead of a leaf node with a element/patches). Prompt the user first. if (CheckAndPromptIfNodeWillLosePatches(newParentNode)) { return; } // If moving element nodes, we need to iterate through all selected treenodes, and remove them from // the parent in which they are selected (which we can determine from the treenode parent), and add them // to the target node. If copying, we need to just add them to the new parent node. foreach (TreeNode treeNode in e.SourceNodes) { ElementNode sourceNode = treeNode.Tag as ElementNode; ElementNode oldParentNode = (treeNode.Parent != null) ? treeNode.Parent.Tag as ElementNode : null; int currentIndex = treeNode.Index; if (e.DragMode == DragDropEffects.Move) { if (index >= 0) { VixenSystem.Nodes.MoveNode(sourceNode, newParentNode, oldParentNode, index); // if we're moving nodes within the same group, but earlier in the group, then increment the target position each time. // This is because when the target is AFTER the current position, the shuffling offsets the nodes so that the target // index can stay the same. This isn't the case for the reverse case. if ((newParentNode != oldParentNode) || (newParentNode == oldParentNode && index < currentIndex)) { index++; } } else { VixenSystem.Nodes.MoveNode(sourceNode, newParentNode, oldParentNode); } } else if (e.DragMode == DragDropEffects.Copy) { if (index >= 0) { // increment the index after every move, so the items are inserted in the correct order (if not, they would be reversed) VixenSystem.Nodes.AddChildToParent(sourceNode, newParentNode, index++); } else { VixenSystem.Nodes.AddChildToParent(sourceNode, newParentNode); } } else { Logging.Warn("ConfigElements: Trying to deal with a drag that is an unknown type!"); } } if (expandNode != null) { expandNode.Expand(); } PopulateNodeTree(); OnDragFinished(); }
protected override void OnDragDrop(DragEventArgs e) { // Check it's a list of nodes being dragged if (e.Data.GetDataPresent(typeof(List <TreeNode>))) { List <TreeNode> dragNodes = (List <TreeNode>)e.Data.GetData(typeof(List <TreeNode>)); // if there was no target, don't do anything if (_dragDestinationNode == null) { CleanupDragVisuals(); return; } // if we're dragging onto one of the selected nodes, then don't do anything if (dragNodes.Contains(_dragDestinationNode)) { CleanupDragVisuals(); return; } // if we're dragging onto one of our children, then don't do anything foreach (TreeNode node in dragNodes) { // there seems to be a weird bug where we can get multiple nodes as drag data; sometimes // 2 copies of the same node, except that one is part of the treeview, and one is not! // (I suspect it is if the client treeview may completely repopulate itself while dragging). // So, make sure the dragged nodes are part of this treeview first. if (node.TreeView != this) { continue; } if (_dragDestinationNode.FullPath.StartsWith(node.FullPath)) { CleanupDragVisuals(); return; } } // before we actually do the dragging of nodes, raise the 'finishing' event. If the // handler wants us to stop, then don't complete the drag. if (DragFinishing != null) { DragFinishingEventArgs ea = new DragFinishingEventArgs(); ea.SourceNodes = dragNodes; ea.TargetNode = _dragDestinationNode; ea.DragBetweenNodes = _dragBetweenState; ea.DragMode = e.Effect; DragFinishing(this, ea); if (!ea.FinishDrag) { CleanupDragVisuals(); return; } } if (e.Effect == DragDropEffects.Move) { foreach (TreeNode node in dragNodes) { node.Remove(); } } // this is pretty freakin' horrible. Needs to be refactored. int i; TreeNodeCollection target; switch (_dragBetweenState) { case DragBetweenNodes.DragAboveTargetNode: if (_dragDestinationNode.Parent == null) { target = Nodes; } else { target = _dragDestinationNode.Parent.Nodes; } i = _dragDestinationNode.Index; foreach (TreeNode node in dragNodes) { target.Insert(i++, node); } break; case DragBetweenNodes.DragBelowTargetNode: // if it's expanded, drop the items into the start of the node's nodes. if (_dragDestinationNode.IsExpanded) { i = 0; foreach (TreeNode node in dragNodes) { _dragDestinationNode.Nodes.Insert(i++, node); } _dragDestinationNode.Expand(); } else { if (_dragDestinationNode.Parent == null) { target = Nodes; } else { target = _dragDestinationNode.Parent.Nodes; } i = _dragDestinationNode.Index + 1; foreach (TreeNode node in dragNodes) { target.Insert(i++, node); } } break; case DragBetweenNodes.DragOnTargetNode: _dragDestinationNode.Nodes.AddRange(dragNodes.ToArray()); _dragDestinationNode.Expand(); break; } // Call drag complete event if (DragComplete != null) { DragSourceDestinationEventArgs ea = new DragSourceDestinationEventArgs(); ea.SourceNodes = dragNodes; ea.TargetNode = _dragDestinationNode; DragComplete(this, ea); } } CleanupDragVisuals(); }