Synchronize DragOver event in two Diagram


I have 2 separate Diagram & the requirement is:

  1. User is allowed to drag ‘Node’ only along Y axis. No dragging along X axis should be allowed.

  2. If user drag ‘Node’ (only along Y axis) in one diagram, then correspondingly some related Node & link objects (based on some common property) of another diagram, should be moved accordingly.

Can you provide me some small sample application to fullfil this requirement?


  1. Do you know the X coordinate value that the node must remain at? If so, you can set the go:Node.MinLocation and go:Node.MaxLocation attached properties to use that X value. For the Y values of these properties you will typically have some reasonable limits, but you can use -Infinity and +Infinity if you really want there to be no limit.

  2. I would use a TwoWay data binding on the go:Node.Location of the node(s) in the first diagram. The node(s) in the second diagram could then data bind go:Node.Location to that same data. You might need to use a converter if you don’t want to use precisely the same values in both diagrams.


But how to catch ‘DragOver’ event to do some task?

I already implemented

Diagram.DragOver event, but it’s never called when I drag any node.

You don’t need to implement that event at all in order to cause the node(s) in the second diagram to move when the user moves the node in the first diagram.


Can you please provide me small sample code for this?

I am not able to implement based on your approach.


It just occurred to me that the UpdateDemo demonstrates this behavior. It depends on two Diagrams sharing the same model, even though separate DataTemplates are used for the Nodes (and two for the Links, too).

Both Node templates are using TwoWay binding on the go:Node.Location. So when the user moves one node, it automatically updates the TestData.Location property. But that change is also propagated to the other Diagram, where the corresponding Node is also data bound to the same property, so that Node moves too.

Of course you don’t care about what most of UpdateDemo demonstrates, although I suggest you look at it closely anyway for instructional reasons.


I am now able to implement my first requirement to allow mevement only along Y axis to use MinLoacion & MaxLocation property.

But for the second requirement, I saw UpdateDemo sample. But in this example, two Diagrams sharing the same model. So if there is any change in any node’s location, then that is also reflected in other diagram. as both objects are linked to the same model.

But in my case, I have two different diagram with two different instance of models having different objects. So how can it be possible without any DragOver event that if user moves a node in one diagram, then it searches nodes & links (having any userdefined same property like ReferenceId) in other diagram & move them accordingly?

If feasible, then please provide me small sample code, so that I can easily understand & implement it.


OK, assuming two Diagrams with independent Models, and also assuming that there is a many-to-many relationship between the nodes in one model with the nodes of the other model:

<UserControl x:Class="TwoModels.TwoModels" xmlns="" xmlns:x="" xmlns:go="" xmlns:local="clr-namespace:TwoModels"> <UserControl.Resources> <DataTemplate x:Key="NodeTemplate1"> <go:NodePanel Sizing="Auto" go:Part.SelectionAdorned="True" go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"> <go:NodeShape go:NodePanel.Figure="Pentagon" Fill="LightBlue" Stroke="Black" StrokeThickness="1" go:Node.PortId="" /> <TextBlock Text="{Binding Path=Data.Key}" Margin="10" /> </go:NodePanel> </DataTemplate> <DataTemplate x:Key="NodeTemplate2"> <StackPanel go:Part.SelectionAdorned="True" go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"> <Ellipse Fill="LightGreen" Width="30" Height="30" go:Node.PortId="" /> <TextBlock Text="{Binding Path=Data.Key}" Foreground="Green" HorizontalAlignment="Center" /> </StackPanel> </DataTemplate> </UserControl.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="These nodes only move vertically" /> <TextBlock Grid.Row="0" Grid.Column="1" Text="These nodes move horizontally when prefixed with the key of a myDiagram1 node" /> <go:Diagram Grid.Row="1" Grid.Column="0" x:Name="myDiagram1" Padding="10" BorderBrush="Blue" BorderThickness="1" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" NodeTemplate="{StaticResource NodeTemplate1}"> <go:Diagram.DraggingTool> <local:CustomDraggingTool Tag="{Binding ElementName=myDiagram2}"/> </go:Diagram.DraggingTool> </go:Diagram> <go:Diagram Grid.Row="1" Grid.Column="1" x:Name="myDiagram2" Padding="10" BorderBrush="Green" BorderThickness="1" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" NodeTemplate="{StaticResource NodeTemplate2}" /> </Grid> </UserControl>

[code]using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using Northwoods.GoXam.Tool;

namespace TwoModels {
public partial class TwoModels : UserControl {
public TwoModels() {

  var model1 = new GraphLinksModel<MyNodeData, String, String, MyLinkData>();
  model1.NodesSource = new ObservableCollection<MyNodeData>() {
    new MyNodeData() { Key="one", Location=new Point(10, 10) },
    new MyNodeData() { Key="two", Location=new Point(110, 10) }
  myDiagram1.Model = model1;

  var model2 = new GraphLinksModel<MyNodeData, String, String, MyLinkData>();
  model2.NodesSource = new ObservableCollection<MyNodeData>() {
    new MyNodeData() { Key="oneA", Location=new Point(10, 10) },
    new MyNodeData() { Key="oneB", Location=new Point(10, 110) },
    new MyNodeData() { Key="three", Location=new Point(110, 210) }
  myDiagram2.Model = model2;


// this DraggingTool is used by myDiagram1, but modifies the node data in myDiagram2.Model
public class CustomDraggingTool : DraggingTool {
public Diagram OtherDiagram {
get { return this.Tag as Diagram; }

// limit movement to be vertical only
protected override Point ComputeMove(Node n, Point newloc, Dictionary<Part, DraggingTool.Info> draggedparts) {
  return new Point(n.Location.X, newloc.Y);

public override void DoActivate() {
  if (this.OtherDiagram != null) this.OtherDiagram.StartTransaction("Diagram1 moves");
public override void DoDeactivate() {
  if (this.OtherDiagram != null) this.OtherDiagram.CommitTransaction("Diagram1 moves");

protected override void DragOver(Point pt, bool moving, bool copying) {
  base.DragOver(pt, moving, copying);
  if (this.OtherDiagram == null) return;
  foreach (Part p in this.DraggedParts.Keys) {
    var n = p as Node;
    if (n == null) continue;  // ignore Links
    var data = n.Data as MyNodeData;
    if (data == null) continue;  // not data bound?
    foreach (var otherdata in this.OtherDiagram.NodesSource as IEnumerable<MyNodeData>) {
      if (otherdata.Key.StartsWith(data.Key)) {
        // move related nodes in X direction just as this node is being dragged in the Y direction
        otherdata.Location = new Point(data.Location.Y, otherdata.Location.Y);


public class MyNodeData : GraphLinksModelNodeData {

public class MyLinkData : GraphLinksModelLinkData<String, String> {


That’s I was looking for.

Thanks a lot for this sample code. Now I got the point.