Ejemplo n.º 1
0
 /// <summary>
 /// Construct a new <see cref="Link"/>, setting its <c>Content</c> and <c>ContentTemplate</c> properties.
 /// </summary>
 /// <param name="linkdata">the data that this link is bound to; must not be a <see cref="Link"/> or any <c>UIElement</c></param>
 /// <param name="model">the model that the <paramref name="linkdata"/> is in</param>
 /// <param name="templ">the <c>DataTemplate</c> for the <c>ContentTemplate</c> property</param>
 /// <param name="category">the category for the link</param>
 /// <returns>a newly created <see cref="Link"/></returns>
 /// <remarks>
 /// <para>
 /// You may wish to override this method in order to customize the <c>DataTemplate</c> used
 /// for the particular <paramref name="linkdata"/>.
 /// </para>
 /// <para>
 /// The implementation of this method should not modify the model.
 /// </para>
 /// </remarks>
 protected virtual Link MakeLinkForData(Object linkdata, IDiagramModel model, DataTemplate templ, String category) {
   Link link = new Link();  // for PartManager.MakeLinkForData
   PartBinding data = new PartBinding(link, linkdata);
   link.Content = data;
   link.DataContext = data;
   link.ContentTemplate = templ;  // for PartManager.MakeLinkForData
   if (category != null && category != "") {
     if (link.Category != category) link.Category = category;
   }
   return link;
 }
Ejemplo n.º 2
0
    /// <summary>
    /// This is called for each <see cref="Northwoods.GoXam.Model.IDiagramModel.Changed"/> event.
    /// </summary>
    /// <param name="e"></param>
    /// <remarks>
    /// <para>
    /// The implementation of this method and the methods that it calls should not modify the model.
    /// </para>
    /// <para>
    /// For small changes such as the addition or removal of node data from the model,
    /// this calls the <see cref="AddNodeForData"/> or <see cref="RemoveNodeForData"/> method.
    /// </para>
    /// <para>
    /// For changes in link relationships in the model, this calls
    /// <see cref="AddLinkForData(Object, Northwoods.GoXam.Model.IDiagramModel)"/>,
    /// <see cref="AddLinkForData(Object, Object, Northwoods.GoXam.Model.IDiagramModel)"/>,
    /// <see cref="RemoveLinkForData(Object, Northwoods.GoXam.Model.IDiagramModel)"/>, or
    /// <see cref="RemoveLinkForData(Object, Object, Northwoods.GoXam.Model.IDiagramModel)"/>.
    /// </para>
    /// <para>
    /// For more wholescale changes, such as a change in the <see cref="Northwoods.GoXam.Model.IDiagramModel.NodesSource"/>,
    /// this will call <see cref="RebuildNodeElements"/> to discard all existing nodes and links and reconstruct
    /// them using the appropriate (and perhaps changed) data templates.
    /// For widespread changes only involving links, this will call <see cref="RebuildLinkElements"/>.
    /// </para>
    /// </remarks>
    public virtual void OnModelChanged(ModelChangedEventArgs e) {
      if (e == null) return;
      if (e.Change == ModelChange.Property) {
        if (this.UpdatesRouteDataPoints && e.PropertyName == "Points") {
          Link link = FindLinkForData(e.Data, this.Diagram.Model);
          if (link != null && !this.IsUpdatingRouteDataPoints) {
            this.IsUpdatingRouteDataPoints = true;
            IList<Point> pts = e.NewValue as IList<Point>;
            if (pts != null && pts.Count() > 1) {
              link.Route.Points = pts;
            } else {
              link.Route.ClearPoints();
            }
            this.IsUpdatingRouteDataPoints = false;
          }
        }
        return;
      }
      VerifyAccess();
      switch (e.Change) {
        // data properties
        case ModelChange.ReplacedReference:
          if (FindNodeForData(e.OldValue, e.Model) != null) {
            RemoveNodeForData(e.OldValue, e.Model);
          }
          if (FindLinkForData(e.OldValue, e.Model) != null) {
            RemoveLinkForData(e.OldValue, e.Model);
          }
          break;

        // model contents and relationships
        case ModelChange.AddedNode:
          AddNodeForData(e.Data, e.Model);
          break;
        case ModelChange.RemovingNode:
          // called before node data is actually removed from the model,
          // when relationships (e.g. with containing group) are known;
          // but won't be called if Model.NodesSource is changed directly,
          // but will be called if someone calls Model.RemoveNode/DeleteNode
          RemoveNodeForData(e.Data, e.Model);
          break;
        case ModelChange.RemovedNode:
          // called after node data is actually removed from the model,
          // but old node data relationships might already be lost
          RemoveNodeForData(e.Data, e.Model);
          break;
        case ModelChange.ChangedParentNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              Object child = e.Data;
              if (e.OldValue != null) RemoveLinkForData(model.FindNodeByKey(e.OldValue), child, model);
              if (e.NewValue != null) AddLinkForData(model.FindNodeByKey(e.NewValue), child, model);
            }
            break;
          }
        case ModelChange.AddedFromNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              AddLinkForData(model.FindNodeByKey(e.NewValue), e.Data, model);
            }
            break;
          }
        case ModelChange.RemovedFromNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              RemoveLinkForData(model.FindNodeByKey(e.OldValue), e.Data, model);
            }
            break;
          }
        case ModelChange.AddedChildNodeKey:
        case ModelChange.AddedToNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              AddLinkForData(e.Data, model.FindNodeByKey(e.NewValue), model);
            }
            break;
          }
        case ModelChange.RemovedChildNodeKey:
        case ModelChange.RemovedToNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              RemoveLinkForData(e.Data, model.FindNodeByKey(e.OldValue), model);
            }
            break;
          }
        case ModelChange.ChangedFromNodeKeys: {
            Object node = e.Data;
            if (node != null) {
              IDiagramModel model = e.Model;
              if (model != null) {
                System.Collections.IEnumerable oldneighborkeys = e.OldValue as System.Collections.IEnumerable;
                System.Collections.IEnumerable newneighborkeys = e.NewValue as System.Collections.IEnumerable;
                if (oldneighborkeys != null) {
                  foreach (Object n in oldneighborkeys) {
                    if (newneighborkeys == null || !ContainsKey(newneighborkeys, n)) {
                      RemoveLinkForData(model.FindNodeByKey(n), node, model);
                    }
                  }
                }
                if (newneighborkeys != null) {
                  foreach (Object n in newneighborkeys) {
                    if (oldneighborkeys == null || !ContainsKey(oldneighborkeys, n)) {
                      AddLinkForData(model.FindNodeByKey(n), node, model);
                    }
                  }
                }
              }
            }
            break;
          }
        case ModelChange.ChangedChildNodeKeys:
        case ModelChange.ChangedToNodeKeys: {
            Object node = e.Data;
            if (node != null) {
              IDiagramModel model = e.Model;
              if (model != null) {
                System.Collections.IEnumerable oldneighborkeys = e.OldValue as System.Collections.IEnumerable;
                System.Collections.IEnumerable newneighborkeys = e.NewValue as System.Collections.IEnumerable;
                if (oldneighborkeys != null && model != null) {
                  foreach (Object n in oldneighborkeys) {
                    if (newneighborkeys == null || !ContainsKey(newneighborkeys, n)) {
                      RemoveLinkForData(node, model.FindNodeByKey(n), model);
                    }
                  }
                }
                if (newneighborkeys != null && model != null) {
                  foreach (Object n in newneighborkeys) {
                    if (oldneighborkeys == null || !ContainsKey(oldneighborkeys, n)) {
                      AddLinkForData(node, model.FindNodeByKey(n), model);
                    }
                  }
                }
              }
            }
            break;
          }
        case ModelChange.ChangedGroupNodeKey: {
            IDiagramModel model = e.Model;
            if (model != null) {
              Node oldsg = FindNodeForData(model.FindNodeByKey(e.OldValue), model);
              if (oldsg != null) {
                oldsg.InvalidateRelationships("GroupNodeChanged");
              }
              Node newsg = FindNodeForData(model.FindNodeByKey(e.NewValue), model);
              if (newsg != null) {
                newsg.InvalidateRelationships("GroupNodeChanged");
                newsg.SortZOrder();
              }
              Node node = FindNodeForData(e.Data, model);
              if (node != null) {
                foreach (Link l in node.LinksConnected) UpdateCachedMembership(model, l);
                if (oldsg != null)
                  OnMemberRemoved(oldsg, node);
                else if (newsg != null)  // and oldsg == null
                  InvalidateDiagramLayout(node, LayoutChange.NodeRemoved);
                if (newsg != null)
                  OnMemberAdded(newsg, node);
                else if (oldsg != null)  // and newsg == null
                  InvalidateDiagramLayout(node, LayoutChange.NodeAdded);
              }
            }
            break;
          }
        case ModelChange.ChangedMemberNodeKeys: {
            Object node = e.Data;
            if (node != null) {
              IDiagramModel model = e.Model;
              if (model != null) {
                Node groupnode = FindNodeForData(node, model);
                System.Collections.IEnumerable oldmemberkeys = e.OldValue as System.Collections.IEnumerable;
                System.Collections.IEnumerable newmemberkeys = e.NewValue as System.Collections.IEnumerable;
                if (oldmemberkeys != null && model != null) {
                  foreach (Object mk in oldmemberkeys) {
                    if (newmemberkeys == null || !ContainsKey(newmemberkeys, mk)) {
                      Node oldmember = FindNodeForData(model.FindNodeByKey(mk), model);
                      if (oldmember != null) {
                        oldmember.InvalidateRelationships("MemberNodeChanged");
                        foreach (Link l in oldmember.LinksConnected) UpdateCachedMembership(model, l);
                        if (groupnode != null)
                          OnMemberRemoved(groupnode, oldmember);
                        else
                          InvalidateDiagramLayout(oldmember, LayoutChange.NodeRemoved);
                      }
                    }
                  }
                }
                if (newmemberkeys != null && model != null) {
                  foreach (Object n in newmemberkeys) {
                    if (oldmemberkeys == null || !ContainsKey(oldmemberkeys, n)) {
                      Node newmember = FindNodeForData(model.FindNodeByKey(n), model);
                      if (newmember != null) {
                        newmember.InvalidateRelationships("MemberNodeChanged");
                        foreach (Link l in newmember.LinksConnected) UpdateCachedMembership(model, l);
                        newmember.SortZOrder();
                        if (groupnode != null)
                          OnMemberAdded(groupnode, newmember);
                        else
                          InvalidateDiagramLayout(newmember, LayoutChange.NodeAdded);
                      }
                    }
                  }
                }
              }
            }
            break;
          }
        case ModelChange.AddedMemberNodeKey: {
            Object nkey = e.NewValue;
            IDiagramModel model = e.Model;
            if (model != null) {
              Node newmember = FindNodeForData(model.FindNodeByKey(nkey), model);
              if (newmember != null) {
                newmember.InvalidateRelationships("MemberNodeAdded");
                foreach (Link l in newmember.LinksConnected) UpdateCachedMembership(model, l);
                newmember.SortZOrder();
                Node groupnode = FindNodeForData(e.Data, model);
                if (groupnode != null)
                  OnMemberAdded(groupnode, newmember);
                else
                  InvalidateDiagramLayout(newmember, LayoutChange.NodeAdded);
              }
            }
            break;
          }
        case ModelChange.RemovedMemberNodeKey: {
            Object okey = e.OldValue;
            IDiagramModel model = e.Model;
            if (model != null) {
              Node oldmember = FindNodeForData(model.FindNodeByKey(okey), model);
              if (oldmember != null) {
                oldmember.InvalidateRelationships("MemberNodeRemoved");
                foreach (Link l in oldmember.LinksConnected) UpdateCachedMembership(model, l);
                Node groupnode = FindNodeForData(e.Data, model);
                if (groupnode != null)
                  OnMemberRemoved(groupnode, oldmember);
                else
                  InvalidateDiagramLayout(oldmember, LayoutChange.NodeRemoved);
              }
            }
            break;
          }

        case ModelChange.AddedLink:
          AddLinkForData(e.Data, e.Model);
          break;
        case ModelChange.RemovingLink:
          RemoveLinkForData(e.Data, e.Model);
          break;
        case ModelChange.RemovedLink:
          RemoveLinkForData(e.Data, e.Model);
          break;
        case ModelChange.ChangedLinkFromPort:
        case ModelChange.ChangedLinkToPort: {
            Link link = FindLinkForData(e.Data, e.Model);
            if (link != null) {
              if (e.NewValue != null) {
                // don't invalidate the route when disconnecting, only when connecting or reconnecting
                link.Route.InvalidateRoute();
              }
              // reset the data binding, in case of bindings such as 
              //  Stroke="{Binding Path=Link.FromNode.Data.Brush}"
              PartBinding data = new PartBinding(link, e.Data);
              link.Content = data;
              link.DataContext = data;
            }
            break;
          }
        case ModelChange.ChangedLinkGroupNodeKey: {
            Link link = FindLinkForData(e.Data, e.Model);
            if (link != null) link.InvalidateRelationships("LinkGroupChanged");
            IDiagramModel model = e.Model;
            if (model != null) {
              Node oldsg = FindNodeForData(model.FindNodeByKey(e.OldValue), model);
              if (oldsg != null) oldsg.InvalidateRelationships("LinkGroupChanged");
              Node newsg = FindNodeForData(model.FindNodeByKey(e.NewValue), model);
              if (newsg != null) {
                Group sg = newsg as Group;
                if (sg != null && link != null) {
                  bool vis = sg.IsExpandedSubGraph;
                  if (link.Visible != vis) link.Visible = vis;
                }
                newsg.InvalidateRelationships("LinkGroupChanged");
              }
            }
            break;
          }
        case ModelChange.ChangedLinkLabelKey: {
            Link link = FindLinkForData(e.Data, e.Model);
            if (link != null) link.InvalidateRelationships("LinkLabelChanged");
            break;
          }
        case ModelChange.ChangedNodeKey: {
            Node n = FindNodeForData(e.Data, e.Model);
            if (n != null) {
              n.InvalidateRelationships("NodeKeyChanged");
            }
            break;
          }
        case ModelChange.ChangedNodeCategory: {
            Object nodedata = e.Data;
            IDiagramModel model = e.Model;
            Node node = FindNodeForData(nodedata, model);
            if (node != null) {
              bool wasselected = node.IsSelected;
              RemoveNodeForData(nodedata, model);
              AddNodeForData(nodedata, model);
              if (wasselected) {
                Node newnode = FindNodeForData(nodedata, model);
                if (newnode != null) newnode.IsSelected = wasselected;
              }
            }
            break;
          }
        case ModelChange.ChangedLinkCategory: {
            Object linkdata = e.Data;
            IDiagramModel model = e.Model;
            Link link = FindLinkForData(linkdata, model);
            if (link != null) {
              bool wasselected = link.IsSelected;
              RemoveLinkForData(linkdata, model);
              AddLinkForData(linkdata, model);
              if (wasselected) {
                Link newlink = FindLinkForData(linkdata, model);
                if (newlink != null) newlink.IsSelected = wasselected;
              }
            }
            break;
          }
        case ModelChange.InvalidateRelationships: {
            Node node = FindNodeForData(e.Data, e.Model);
            if (node != null) {
              node.Remeasure();
              Diagram.InvokeLater(this.Diagram, () => { node.InvalidateRelationships("ChangedNodeGeometry"); });
            }
            break;
          }

        // model discovery
        case ModelChange.ChangedNodesSource: {
            Diagram diagram = this.Diagram;
            IDiagramModel model = e.Model;
            if (diagram != null && model != null && diagram.NodesSource != model.NodesSource) {
              diagram.NodesSource = model.NodesSource;
            }
            RebuildNodeElements();  // also calls RebuildLinkElements
            if (diagram != null && model != null && !model.IsChangingModel) {
              diagram.RelayoutDiagram();
            }
            break;
          }
        case ModelChange.ChangedNodeKeyPath:
        case ModelChange.ChangedNodeCategoryPath:
        case ModelChange.ChangedNodeIsGroupPath:
        case ModelChange.ChangedGroupNodePath:
        case ModelChange.ChangedMemberNodesPath:
        case ModelChange.ChangedNodeIsLinkLabelPath: {
            RebuildNodeElements();  // also calls RebuildLinkElements
            Diagram diagram = this.Diagram;
            IDiagramModel model = e.Model;
            if (diagram != null && model != null && !model.IsChangingModel) {
              diagram.RelayoutDiagram();
            }
            break;
          }
        case ModelChange.ChangedLinksSource: {
            Diagram diagram = this.Diagram;
            IDiagramModel model = e.Model;
            if (diagram != null && model != null) {
              ILinksModel lmodel = model as ILinksModel;
              if (lmodel != null && diagram.LinksSource != lmodel.LinksSource) {
                diagram.LinksSource = lmodel.LinksSource;
              }
            }
            RebuildLinkElements();
            if (diagram != null && model != null && !model.IsChangingModel) {
              diagram.RelayoutDiagram();
            }
            break;
          }
        case ModelChange.ChangedLinkFromPath:
        case ModelChange.ChangedLinkToPath:
        case ModelChange.ChangedFromNodesPath:
        case ModelChange.ChangedToNodesPath:
        case ModelChange.ChangedLinkLabelNodePath: {
            RebuildLinkElements();
            Diagram diagram = this.Diagram;
            IDiagramModel model = e.Model;
            if (diagram != null && model != null && !model.IsChangingModel) {
              diagram.RelayoutDiagram();
            }
            break;
          }
        //case ModelChange.ChangedParentPortParameterPath:
        //case ModelChange.ChangedChildPortParameterPath:
        case ModelChange.ChangedLinkFromParameterPath:
        case ModelChange.ChangedLinkToParameterPath:
        case ModelChange.ChangedLinkCategoryPath:
          RebuildLinkElements();
          break;

        case ModelChange.StartedTransaction:
          //?? produce routed event
          break;
        case ModelChange.CommittedTransaction: {
            //?? produce routed event
            String reason = e.Data as String;
            if (reason != "Layout" && reason != "DelayedRouting") {  // check for this case to avoid infinite loop
              Diagram diagram = this.Diagram;
              if (diagram == null) break;
              IDiagramModel model = diagram.Model;
              if (model != null) model.ClearUnresolvedReferences();
              DiagramPanel panel = diagram.Panel;
              if (panel != null) panel.UpdateScrollTransform();
              LayoutManager laymgr = diagram.LayoutManager;
              if (laymgr != null) laymgr.InvokeLayoutDiagram("CommittedTransaction");
              diagram.UpdateCommands();
            }
            break;
          }
        case ModelChange.RolledBackTransaction: {
            //?? produce routed event
            String reason = e.Data as String;
            if (reason != "Layout" && reason != "DelayedRouting") {  // check for this case to avoid infinite loop
              Diagram diagram = this.Diagram;
              if (diagram == null) break;
              IDiagramModel model = diagram.Model;
              if (model != null) model.ClearUnresolvedReferences();
              diagram.UpdateCommands();
            }
            break;
          }

        case ModelChange.StartingUndo:
        case ModelChange.StartingRedo:
          break;
        case ModelChange.FinishedUndo:
        case ModelChange.FinishedRedo: {
            //?? produce routed event
            Diagram diagram = this.Diagram;
            if (diagram == null) break;
            DiagramPanel panel = diagram.Panel;
            if (panel == null) break;
            // force everything to be remeasured
            foreach (UIElement elt in panel.Children) {
              NodeLayer nlay = elt as NodeLayer;
              if (nlay != null) {
                if (nlay.IsTemporary) continue;
                foreach (Node n in nlay.Nodes) {
                  n.Remeasure();
                }
              } else {
                LinkLayer llay = elt as LinkLayer;
                if (llay != null) {
                  if (llay.IsTemporary) continue;
                  foreach (Link l in llay.Links) {
                    l.Remeasure();
                  }
                }
              }
            }
            panel.UpdateScrollTransform();
            panel.InvokeUpdateDiagramBounds("Undo/Redo");
            diagram.UpdateCommands();
            break;
          }

        // model state
        case ModelChange.ChangedName:
        case ModelChange.ChangedDataFormat:
        case ModelChange.ChangedModifiable:
        case ModelChange.ChangedValidCycle:
        case ModelChange.ChangedValidUnconnectedLinks: {
            Diagram diagram = this.Diagram;
            if (diagram == null) break;
            diagram.UpdateCommands();
            break;
          }
        case ModelChange.ChangedCopyingGroupCopiesMembers:
        case ModelChange.ChangedCopyingLinkCopiesLabel:
        case ModelChange.ChangedRemovingGroupRemovesMembers:
        case ModelChange.ChangedRemovingLinkRemovesLabel:
          break;
        default:
          Diagram.Error("Diagram did not handle Model change: " + e.Change.ToString());
          break;
      }
    }
Ejemplo n.º 3
0
 /// <summary>
 /// Construct a new <see cref="Node"/>, setting its <c>Content</c> and <c>ContentTemplate</c> properties.
 /// </summary>
 /// <param name="nodedata">the data that this node is bound to; must not be a <see cref="Node"/> or any <c>UIElement</c></param>
 /// <param name="model">the model that the <paramref name="nodedata"/> is in</param>
 /// <param name="isgroup">whether the node should be a <see cref="Group"/></param>
 /// <param name="islinklabel">whether the node acts as the label node for a link</param>
 /// <param name="category">the category of the node</param>
 /// <param name="templ">the <c>DataTemplate</c> for the <c>ContentTemplate</c> property</param>
 /// <returns>a newly created <see cref="Node"/> or <see cref="Group"/>,
 /// bound to <paramref name="nodedata"/> via a <see cref="PartBinding"/></returns>
 /// <remarks>
 /// <para>
 /// You may wish to override this method in order to customize the <c>DataTemplate</c> used
 /// for the particular <paramref name="nodedata"/>.
 /// Less frequently you will want to override this method to construct a subclass of <see cref="Node"/>
 /// where you have overridden one of the node methods, such as <see cref="Node.FindPort"/>.
 /// </para>
 /// <para>
 /// The implementation of this method should not modify the model.
 /// </para>
 /// </remarks>
 protected virtual Node MakeNodeForData(Object nodedata, IDiagramModel model, bool isgroup, bool islinklabel, String category, DataTemplate templ) {
   Node node = (isgroup ? new Group() : new Node());  // for PartManager.MakeNodeForData
   PartBinding data = new PartBinding(node, nodedata);
   node.Content = data;
   node.DataContext = data;
   node.ContentTemplate = templ;  // for PartManager.MakeNodeForData
   node.IsLinkLabel = islinklabel;
   if (category != null && category != "") {
     if (node.Category != category) node.Category = category;
   }
   return node;
 }