Snap to grid customization

Hi, I have a few questions about how I can customize snapping to the grid with respect to drag/drop. Thanks.

  • What is the best way to have a node move freely while dragging but snap to the grid when it is dropped – when is the best time to toggle Diagram.GridSnapEnabled?
  • How can I snap each node to the Spot.TopLeft corner of the grid cell if every node has Node.LocationSpot = Spot.Center?
  • Can I make different nodes have different snap cell sizes? Perhaps via Diagram.GridSnapCellSize? (I am unsure if Node.DragOverSnapCellSize would be useful here)

To allow free movement until a drop happens, use this replacement DraggingTool:

  public class SnapOnDropDraggingTool : DraggingTool {
    public SnapOnDropDraggingTool() {
      this.DragOverSnapArea = DragOverSnapArea.None;
    }
    public override void DoDrop(DragEventArgs e) {
      this.DragOverSnapArea = DragOverSnapArea.DiagramAndNodes;
      base.DoDrop(e);
      this.DragOverSnapArea = DragOverSnapArea.None;
    }
  }

It’s always the Node.Location point that is lined up when snapping to some grid cell point.

Node.DragOverSnapCellSize is useful when a stationary object is used for snapping. For example, the Planogram sample uses that for the “Racks” and the “Shelves”. But I think you’re asking about having individual Nodes snap differently.

So I think you need to override DraggingTool.ComputeMove. This provides the most general control over where any Node goes. For your information, it is implemented as follows:

    protected virtual Point ComputeMove(Node n, Point newloc, Dictionary<Part, Info> draggedparts) {
      if (n == null) return newloc;
      Point pt = newloc;
      Node snapper = this.CurrentSnapper;
      // only consider snapping to nodes if DragOverSnapArea includes Nodes
      if (snapper != null && (this.DragOverSnapArea&DragOverSnapArea.Nodes) != 0 && ConsiderSnapTo(n, newloc, snapper, draggedparts)) {
        pt = SnapTo(n, newloc, snapper, draggedparts);
      }
      // only consider diagram snapping if there's no SNAPPER node and DragOverSnapArea includes Diagram
      if (snapper == null && (this.DragOverSnapArea&DragOverSnapArea.Diagram) != 0) {
        pt = SnapTo(n, newloc, null, draggedparts);
      }
      Point min = n.MinLocation;
      Point max = n.MaxLocation;
      return new Point(Math.Max(min.X, Math.Min(pt.X, max.X)), Math.Max(min.Y, Math.Min(pt.Y, max.Y)));
    }

However, I am guessing that you don’t care about trying to snap a Node according to another Node, the way that the Planogram sample does. So really the functionality you need to implement is:

    protected override Point ComputeMove(Node n, Point newloc, Dictionary<Part, Info> draggedparts) {
      if (n == null) return newloc;
      Point pt = newloc;
      if (this.DragOverSnapArea & DragOverSnapArea.Diagram) != 0) {
        // adjust pt.X and pt.Y so that node n is lined up the way that you want
        . . .
      }
      Point min = n.MinLocation;
      Point max = n.MaxLocation;
      return new Point(Math.Max(min.X, Math.Min(pt.X, max.X)), Math.Max(min.Y, Math.Min(pt.Y, max.Y)));
    }

The SnapOnDropDraggingTool does not work – the nodes do not snap to the grid upon a drop. I found a way to make the nodes snap to the grid upon a drop by overriding DoMouseUp and executing

this.DragOverSnapArea = DragOverSnapArea.DiagramAndNodes;

before calling the base function. However this does not work when dropping from a palette as it appears DoMouseUp is not called. Any ideas? Thanks.

Overriding ComputeMove didn’t work for you?

I haven’t gotten to customizing for different nodes yet, I’m just trying to have the nodes move freely while dragging then snap upon dropping. It didn’t work in DoDrop. ComputeMove relies on this.DragOverSnapArea, so I need to find the right place to change between DragOverSnapArea.None and DragOverSnapArea.Diagram.

The target Diagram’s DraggingTool.DoDrop isn’t called for you upon an external drop?

It is being called, but the nodes aren’t snapping to the grid. I can’t figure out what is causing this behavior.

I am still struggling with DraggingTool.DragOverSnapArea. I am trying to override ComputeMove but this if statement doesn’t return true:

if (this.DragOverSnapArea & DragOverSnapArea.Diagram) != 0) {
    // adjust pt.X and pt.Y so that node n is lined up the way that you want
    . . .
  }

I don’t understand the order of method calls upon a drop. I want to set DraggingTool.DragOverSnapArea to DragOverSnapArea.Diagram right when a drop happends before ComputeMove is called.

Yes, that’s why the SnapOnDropDraggingTool sets DragOverSnapArea just before executing the normal DoDrop behavior.

Thank you, I discovered my problem was elsewhere.