private void treeviewDragVerifyHandler(object sender, DragVerifyEventArgs e) { // we need to go through all nodes that would be moved (source nodes), and check if there's any // problem moving any of them to the target node (circular references, etc.), since it's possible // for a element to exist multiple times in the treeview as different treenodes. List <ElementNode> nodes = new List <ElementNode>(e.SourceNodes.Select(x => x.Tag as ElementNode)); // now get a list of invalid children for this target node, and check all the remaining nodes against it. // If any of them fail, the entire operation should fail, as it would be an invalid move. // the target node will be the actual target node if it is directly on it, otherwise it would be the parent // of the target node if it would be dragged above/below the taget element (as it would be put alongside it). // also keep track of the 'permitted' nodes: this is used when dragging alongside another element: any children // of the new parent node are considered OK, as we might just be shuffling them around. Normally, this would // be A Bad Thing, since it would seem like we're adding a child to the group it's already in. (This is only // the case when moving; if copying, it should be disabled. That's checked later.) IEnumerable <ElementNode> invalidNodesForTarget = null; IEnumerable <ElementNode> permittedNodesForTarget = null; if (e.DragBetweenNodes == DragBetweenNodes.DragOnTargetNode || e.DragBetweenNodes == DragBetweenNodes.DragBelowTargetNode && e.TargetNode.IsExpanded) { invalidNodesForTarget = (e.TargetNode.Tag as ElementNode).InvalidChildren(); permittedNodesForTarget = new HashSet <ElementNode>(); } else { if (e.TargetNode.Parent == null) { invalidNodesForTarget = VixenSystem.Nodes.InvalidRootNodes; permittedNodesForTarget = VixenSystem.Nodes.GetRootNodes(); } else { invalidNodesForTarget = (e.TargetNode.Parent.Tag as ElementNode).InvalidChildren(); permittedNodesForTarget = (e.TargetNode.Parent.Tag as ElementNode).Children; } } if ((e.KeyState & 8) != 0) { // the CTRL key e.DragMode = DragDropEffects.Copy; permittedNodesForTarget = new HashSet <ElementNode>(); } else { e.DragMode = DragDropEffects.Move; } IEnumerable <ElementNode> invalidSourceNodes = invalidNodesForTarget.Intersect(nodes); if (invalidSourceNodes.Any()) { if (invalidSourceNodes.Intersect(permittedNodesForTarget).Count() == invalidSourceNodes.Count()) { e.ValidDragTarget = true; } else { e.ValidDragTarget = false; } } else { e.ValidDragTarget = true; } }
protected override void OnDragOver(DragEventArgs e) { // Change any previous node back if (_dragDestinationNode != null) { DrawNodeAsNormal(_dragDestinationNode); } // Get the node from the mouse position, colour it Point pt = PointToClient(new Point(e.X, e.Y)); _dragDestinationNode = GetNodeAt(pt); if (_dragDestinationNode != null) { // try and figure out if we would be dragging 'between' nodes. if (_dragDestinationNode.Bounds.Contains(pt) && pt.Y - _dragDestinationNode.Bounds.Top <= 3) { _dragBetweenState = DragBetweenNodes.DragAboveTargetNode; } else if (_dragDestinationNode.Bounds.Contains(pt) && _dragDestinationNode.Bounds.Bottom - pt.Y <= 3) { _dragBetweenState = DragBetweenNodes.DragBelowTargetNode; } else { _dragBetweenState = DragBetweenNodes.DragOnTargetNode; } // figure out where to draw the dotted line to show where it would be moving to. if (DraggingBetweenRows) { if (_dragBetweenState == DragBetweenNodes.DragAboveTargetNode) { _dragBetweenRowsDrawLineStart = new Point(_dragDestinationNode.Bounds.Left, _dragDestinationNode.Bounds.Top); _dragBetweenRowsDrawLineEnd = new Point(_dragDestinationNode.Bounds.Right + 10, _dragDestinationNode.Bounds.Top); } else if (_dragBetweenState == DragBetweenNodes.DragBelowTargetNode) { _dragBetweenRowsDrawLineStart = new Point(_dragDestinationNode.Bounds.Left, _dragDestinationNode.Bounds.Bottom); _dragBetweenRowsDrawLineEnd = new Point(_dragDestinationNode.Bounds.Right + 10, _dragDestinationNode.Bounds.Bottom); } else { _dragBetweenRowsDrawLineStart = new Point(-1, -1); _dragBetweenRowsDrawLineEnd = new Point(-1, -1); } if (_dragLastLineDrawnY != _dragBetweenRowsDrawLineStart.Y) { Invalidate(); _dragLastLineDrawnY = _dragBetweenRowsDrawLineStart.Y; } } } else { } // get the nodes that are being dragged from the drag data List <TreeNode> dragNodes = null; if (e.Data.GetDataPresent(typeof(List <TreeNode>))) { dragNodes = (List <TreeNode>)e.Data.GetData(typeof(List <TreeNode>)); } if (dragNodes != null) { // if the target node is in the dragged nodes, it's not a valid point: don't select it if (_dragDestinationNode != null && dragNodes.Contains(_dragDestinationNode)) { _dragDestinationNode = null; } } if (dragNodes != null && _dragDestinationNode != null) { // if there's been a verification call setup, call it to check that the // target node is OK. otherwise, assume it is. if (DragOverVerify != null) { DragVerifyEventArgs ea = new DragVerifyEventArgs(); ea.SourceNodes = dragNodes; ea.TargetNode = _dragDestinationNode; ea.DragBetweenNodes = _dragBetweenState; ea.KeyState = e.KeyState; ea.DragMode = _dragDefaultMode; DragOverVerify(this, ea); if (ea.ValidDragTarget) { e.Effect = ea.DragMode; } else { e.Effect = DragDropEffects.None; _dragDestinationNode = null; } } else { e.Effect = _dragDefaultMode; } if (_dragDestinationNode != null && !DraggingBetweenRows) { DrawNodeAsDragDestination(_dragDestinationNode); } } else { e.Effect = DragDropEffects.None; } // Scrolling down/up if (pt.Y + 10 > ClientSize.Height) { SendMessage(Handle, 277, (IntPtr)1, 0); } else if (pt.Y < Top + 10) { SendMessage(Handle, 277, (IntPtr)0, 0); } }