/// <summary> /// Visits the <see cref="ReferenceEnumerable"/> contained in the given node, if any. /// </summary> /// <param name="node">The node being visited.</param> protected virtual void VisitItemTargets([NotNull] IObjectNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } var enumerableReference = node.ItemReferences; if (enumerableReference != null) { foreach (var reference in enumerableReference) { if (reference.TargetNode == null) { continue; } if (ShouldVisitTargetItem(node, reference.Index)) { CurrentPath.PushIndex(reference.Index); VisitReference(node, reference); CurrentPath.Pop(); } } } }
public static GraphNodePath From(IGraphNode root, [NotNull] MemberPath memberPath, out NodeIndex index) { if (memberPath == null) { throw new ArgumentNullException(nameof(memberPath)); } var result = new GraphNodePath(root); index = NodeIndex.Empty; var memberPathItems = memberPath.Decompose(); for (int i = 0; i < memberPathItems.Count; i++) { var memberPathItem = memberPathItems[i]; bool lastItem = i == memberPathItems.Count - 1; if (memberPathItem.MemberDescriptor != null) { result.PushMember(memberPathItem.MemberDescriptor.Name); } else if (memberPathItem.GetIndex() != null) { var localIndex = new NodeIndex(memberPathItem.GetIndex()); if (lastItem) { // If last item, we directly return the index rather than add it to the path index = localIndex; } else { result.PushIndex(localIndex); } } // Don't apply Target on last item if (!lastItem) { // If this is a reference, add a target element to the path var node = result.GetNode(); var objectReference = (node as IMemberNode)?.TargetReference; if (objectReference?.TargetNode != null) { result.PushTarget(); } } } return(result); }
private void ContentFinalizeChange(object sender, [NotNull] INodeChangeEventArgs e) { var visitor = CreateVisitor(); visitor.Visiting += (node, path) => RegisterNode(node); switch (e.ChangeType) { case ContentChangeType.ValueChange: case ContentChangeType.CollectionUpdate: // The changed node itself is still valid, we don't want to re-register it visitor.SkipRootNode = true; visitor.Visit(e.Node); // TODO: In case of CollectionUpdate we could probably visit only the target node of the corresponding index break; case ContentChangeType.CollectionAdd: if (e.Node.IsReference && e.NewValue != null) { var objectNode = (IObjectNode)e.Node; IGraphNode addedNode; Index index; var arg = (ItemChangeEventArgs)e; if (!arg.Index.IsEmpty) { index = arg.Index; addedNode = objectNode.ItemReferences[arg.Index].TargetNode; } else { // TODO: review this var reference = objectNode.ItemReferences.First(x => x.TargetNode.Retrieve() == e.NewValue); index = reference.Index; addedNode = reference.TargetNode; } if (addedNode != null && visitor.ShouldVisitTargetItem(objectNode, index)) { var path = new GraphNodePath(e.Node); path.PushIndex(index); visitor.Visit(addedNode, e.Node as MemberNode, path); } } break; } }