diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs index 85084708cb..473808768c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs @@ -12,20 +12,39 @@ using System.Windows; namespace Debugger.AddIn.Visualizers.Graph.Layout { /// - /// Node with added position information. + /// ObjectNode with added position information. /// public class PositionedNode { private ObjectNode objectNode; + /// + /// Underlying ObjectNode. + /// public ObjectNode ObjectNode { get { return objectNode; } } - public PositionedNode(NodeControl nodeVisualControl, ObjectNode objectNode) + private List properties = new List(); + public List Properties + { + get + { + return this.properties; + } + } + + /// + /// Creates new PositionedNode. + /// + /// Underlying ObjectNode. + public PositionedNode(ObjectNode objectNode) { - this.nodeVisualControl = nodeVisualControl; this.objectNode = objectNode; + + this.nodeVisualControl = new NodeControl(); + this.nodeVisualControl.GraphNode = this.objectNode; // display + this.nodeVisualControl.Measure(new Size(500, 500)); } public double Left { get; set; } @@ -67,7 +86,10 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout { get { - return new PositionedEdge[]{}; + foreach (PositionedNodeProperty property in this.Properties) + { + yield return property.Edge; + } } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs new file mode 100644 index 0000000000..4fdf2529dd --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs @@ -0,0 +1,39 @@ +// +// +// +// +// $Revision$ +// +using System; + +namespace Debugger.AddIn.Visualizers.Graph.Layout +{ + /// + /// with outgoing . + /// + public class PositionedNodeProperty + { + /// + /// Creates new PositionedNodeProperty. + /// + /// Underlying + public PositionedNodeProperty(ObjectProperty objectProperty) + { + this.objectProperty = objectProperty; + } + + private ObjectProperty objectProperty; + /// + /// Underlying . + /// + public ObjectProperty ObjectProperty + { + get { return objectProperty; } + } + + /// + /// Edge outgoing from this property to another . + /// + public PositionedEdge Edge { get; set; } + } +} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/BoxDotFormatter.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/BoxDotFormatter.cs new file mode 100644 index 0000000000..91a413b8a3 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/BoxDotFormatter.cs @@ -0,0 +1,44 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Text; +using System.Windows; + +namespace Debugger.AddIn.Visualizers.Graph.Layout +{ + /// + /// that treats node as a atomic "box". Edges go from box to box. + /// + public class BoxDotFormatter : DotFormatter + { + public BoxDotFormatter(PositionedGraph posGraph) : base(posGraph) + { + } + + protected override void appendPosNode(PositionedNode node, StringBuilder builder) + { + string nodeName = genId.GetNextId().ToString(); + nodeNames[node] = nodeName; + + Rect neatoInput = transform.NodeToNeatoInput(node); + + string dotFormatNode = + string.Format(formatCulture, + "{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\"];", + nodeName, neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height); + builder.AppendLine(dotFormatNode); + } + + protected override void appendPosEdge(PositionedEdge edge, StringBuilder builder) + { + string sourceNodeName = nodeNames[edge.SourceNode]; + string targetNodeName = nodeNames[edge.TargetNode]; + + builder.AppendLine(string.Format("{0} -> {1}", sourceNodeName, targetNodeName)); + } + } +} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotGraph.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotFormatter.cs similarity index 66% rename from src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotGraph.cs rename to src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotFormatter.cs index f6e4333d49..b56f309cdf 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotGraph.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/DotFormatter.cs @@ -17,24 +17,24 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout /// /// Converts /// Used for generating node and edge names. /// - private IdGenerator genId = new IdGenerator(); + protected IdGenerator genId = new IdGenerator(); - public DotGraph(PositionedGraph posGraph) + public DotFormatter(PositionedGraph posGraph) { if (posGraph.Nodes.Count() == 0) { @@ -44,54 +44,33 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout this.transform = new NeatoPositionTransform(this.posGraph.BoundingRect); } + protected abstract void appendPosNode(PositionedNode node, StringBuilder builder); + + protected abstract void appendPosEdge(PositionedEdge edge, StringBuilder builder); + /// - /// Gets Graphviz's dot format string for the positioned graph. + /// Gets Graphviz's dot format string for wrapped positioned graph. /// - public string DotGraphString + public string OutputGraphInDotFormat() { - get + StringBuilder dotStringBuilder = new StringBuilder("digraph G { node [shape = box];"); + + foreach (PositionedNode posNode in this.posGraph.Nodes) { - StringBuilder dotStringBuilder = new StringBuilder("digraph G { node [shape = box];"); - - foreach (PositionedNode posNode in this.posGraph.Nodes) - { - appendPosNode(posNode, dotStringBuilder); - } - foreach (PositionedEdge posEdge in this.posGraph.Edges) - { - appendPosEdge(posEdge, dotStringBuilder); - } - - dotStringBuilder.AppendLine("}"); - return dotStringBuilder.ToString(); + appendPosNode(posNode, dotStringBuilder); + } + foreach (PositionedEdge posEdge in this.posGraph.Edges) + { + appendPosEdge(posEdge, dotStringBuilder); } - } - - private void appendPosNode(PositionedNode node, StringBuilder builder) - { - string nodeName = genId.GetNextId().ToString(); - nodeNames[node] = nodeName; - - Rect neatoInput = transform.NodeToNeatoInput(node); - - string dotFormatNode = - string.Format(formatCulture, - "{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\"];", - nodeName, neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height); - builder.AppendLine(dotFormatNode); - } - - private void appendPosEdge(PositionedEdge edge, StringBuilder builder) - { - string sourceNodeName = nodeNames[edge.SourceNode]; - string targetNodeName = nodeNames[edge.TargetNode]; - builder.AppendLine(string.Format("{0} -> {1}", sourceNodeName, targetNodeName)); + dotStringBuilder.AppendLine("}"); + return dotStringBuilder.ToString(); } private bool validateSplinePoints(PositionedEdge edge) { - // must have correct number of points: one start point and 3 points for every bezier segment + // must have correct number of points: one start point and 3 points per bezier segment return ((edge.SplinePoints.Count - 1) % 3) == 0; } @@ -112,6 +91,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout transform.NeatoShiftX = neatoFirstNodePos.X - firstNodePosOur.X; transform.NeatoShiftY = neatoFirstNodePos.Y - firstNodePosOur.Y; + // assume that edges on output are in the same order as posGraph.Edges (!) foreach (PositionedEdge posEdge in posGraph.Edges) { skipAfterPattern(reader, "edge "); diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs index 9df8d0b94c..ccdf153d38 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/NeatoEdgeRouter.cs @@ -30,14 +30,19 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout /// with preserved node positions and calculated edge positions. public PositionedGraph CalculateEdges(PositionedGraph graphWithNodesPositioned) { - DotGraph dotGraph = new DotGraph(graphWithNodesPositioned); + DotFormatter dotFormatter = new RecordDotFormatter(graphWithNodesPositioned); + // start Neato.exe NeatoProcess neatoProcess = NeatoProcess.Start(); - // convert PosGraph to .dot string, pass to neato.exe - string dotGraphStringWithPositions = neatoProcess.CalculatePositions(dotGraph.DotGraphString); + + // convert PosGraph to .dot string + string dotGraphString = dotFormatter.OutputGraphInDotFormat(); + + // pass to neato.exe + string dotGraphStringWithPositions = neatoProcess.CalculatePositions(dotGraphString); // parse edge positions from neato's plain output format - PositionedGraph result = dotGraph.ParseEdgePositions(dotGraphStringWithPositions); + PositionedGraph result = dotFormatter.ParseEdgePositions(dotGraphStringWithPositions); return result; } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/RecordDotFormatter.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/RecordDotFormatter.cs new file mode 100644 index 0000000000..a70eaf28b3 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/RecordDotFormatter.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision$ +// +using System; +using System.Text; +using System.Windows; + +namespace Debugger.AddIn.Visualizers.Graph.Layout +{ + /// + /// that treats nodes as records of properties. + /// Edges start at property, end at node. + /// + public class RecordDotFormatter : DotFormatter + { + public RecordDotFormatter(PositionedGraph posGraph) : base(posGraph) + { + } + + protected override void appendPosNode(PositionedNode node, StringBuilder builder) + { + string nodeName = genId.GetNextId().ToString(); + nodeNames[node] = nodeName; + + Rect neatoInput = transform.NodeToNeatoInput(node); + + /*LEFT [ + pos="0,0!" + width="1", height="1" + label = " a| b| c|d"];*/ + + StringBuilder recordLabel = new StringBuilder(); + + + string dotFormatNode = + string.Format(formatCulture, + "{0} [pos=\"{1},{2}!\" width=\"{3}\" height=\"{4}\" label=\"{5}\"];", + nodeName, + neatoInput.Location.X, neatoInput.Location.Y, neatoInput.Width, neatoInput.Height, + recordLabel.ToString()); + builder.AppendLine(dotFormatNode); + } + + protected override void appendPosEdge(PositionedEdge edge, StringBuilder builder) + { + string sourceNodeName = nodeNames[edge.SourceNode]; + string targetNodeName = nodeNames[edge.TargetNode]; + + builder.AppendLine(string.Format("{0} -> {1}", sourceNodeName, targetNodeName)); + } + } +} diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs index ae7f156e1d..36710219f5 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeEdge.cs @@ -9,9 +9,13 @@ using System; namespace Debugger.AddIn.Visualizers.Graph.Layout { /// - /// Description of TreeEdge. + /// Edge in the tree-layouted . /// - public class TreeEdge : PositionedEdge + public class TreeGraphEdge : PositionedEdge { + /// + /// Is this a main edges making up the tree? + /// + public bool IsTreeEdge { get; set; } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs index 20160454e6..8ddc37cea7 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs @@ -57,11 +57,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout { seenNodes.Add(objectGraphNode, null); - NodeControl nodeVisualControl = new NodeControl(); - nodeVisualControl.GraphNode = objectGraphNode; - nodeVisualControl.Measure(new Size(500, 500)); - - TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, nodeVisualControl, objectGraphNode); + TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, objectGraphNode); newTreeNode.HorizontalMargin = horizNodeMargin; newTreeNode.VerticalMargin = vertNodeMargin; resultGraph.nodes.Add(newTreeNode); @@ -73,17 +69,22 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout if (property.TargetNode != null) { ObjectNode neighbor = property.TargetNode; + TreeNode targetTreeNode = null; + bool newEdgeIsTreeEdge = false; if (seenNodes.ContainsKey(neighbor)) { - newTreeNode.AdditionalNeighbors.Add(new TreeEdge { Name = property.Name, SourceNode = newTreeNode, TargetNode = treeNodeFor[neighbor]}); + targetTreeNode = treeNodeFor[neighbor]; + newEdgeIsTreeEdge = false; } else { - TreeNode newChild = buildTreeRecursive(neighbor); - newTreeNode.ChildEdges.Add(new TreeEdge { Name = property.Name, SourceNode = newTreeNode, TargetNode = newChild}); - - subtreeSize += newChild.SubtreeSize; + targetTreeNode = buildTreeRecursive(neighbor); + newEdgeIsTreeEdge = true; + subtreeSize += targetTreeNode.SubtreeSize; } + var posNodeProperty = new PositionedNodeProperty(property); + posNodeProperty.Edge = new TreeGraphEdge { IsTreeEdge = newEdgeIsTreeEdge, Name = property.Name, SourceNode = newTreeNode, TargetNode = targetTreeNode }; + newTreeNode.Properties.Add(posNodeProperty); } } subtreeSize = Math.Max(newTreeNode.LateralSizeWithMargin, subtreeSize); diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs index b803e6a1b2..5da9609310 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs @@ -11,18 +11,19 @@ using Debugger.AddIn.Visualizers.Graph.Drawing; namespace Debugger.AddIn.Visualizers.Graph.Layout { /// - /// Abstract ancestor of TreeNodeLR and TreeNodeTB. + /// Node in tree-layouted . + /// This is the abstract ancestor of TreeNodeLR and TreeNodeTB. /// There are 2 dimensions - "main" and "lateral". /// Main dimension is the dimension in which the graph depth grows (vertical when TB, horizontal when LR). /// Lateral dimension is the other dimension. Siblings are placed next to each other in Lateral dimension. /// public abstract class TreeNode : PositionedNode { - public static TreeNode Create(LayoutDirection direction, NodeControl nodeVisualControl, ObjectNode objectNode) + public static TreeNode Create(LayoutDirection direction, ObjectNode objectNode) { switch (direction) { - case LayoutDirection.TopBottom: return new TreeNodeTB(nodeVisualControl, objectNode); - case LayoutDirection.LeftRight: return new TreeNodeLR(nodeVisualControl, objectNode); + case LayoutDirection.TopBottom: return new TreeNodeTB(objectNode); + case LayoutDirection.LeftRight: return new TreeNodeLR(objectNode); default: throw new DebuggerVisualizerException("Unsupported layout direction: " + direction.ToString()); } } @@ -30,7 +31,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout public double HorizontalMargin { get; set; } public double VerticalMargin { get; set; } - protected TreeNode(NodeControl nodeVisualControl, ObjectNode objectNode) : base(nodeVisualControl, objectNode) + protected TreeNode(ObjectNode objectNode) : base(objectNode) { } @@ -51,12 +52,17 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout public abstract double MainMargin { get; } public abstract double LateralMargin { get; } - private List childs = new List(); - public List ChildEdges + public IEnumerable ChildEdges { - get - { - return childs; + get + { + foreach (TreeGraphEdge childEdge in Edges) + { + if (childEdge.IsTreeEdge) + { + yield return childEdge; + } + } } } @@ -64,28 +70,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout { get { - foreach (TreeEdge childEdge in ChildEdges) - yield return (TreeNode)childEdge.TargetNode; - } - } - - private List additionalNeighbors = new List(); - public List AdditionalNeighbors - { - get - { - return additionalNeighbors; - } - } - - public override IEnumerable Edges - { - get - { - foreach (TreeEdge childEdge in ChildEdges) - yield return childEdge; - foreach (TreeEdge neighborEdge in AdditionalNeighbors) - yield return neighborEdge; + foreach (PositionedEdge outEdge in this.ChildEdges) + yield return (TreeNode)outEdge.TargetNode; } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs index 0b668d5f44..916ea5eb4e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout /// public class TreeNodeLR: TreeNode { - public TreeNodeLR(NodeControl nodeControl, ObjectNode objectNode) : base(nodeControl, objectNode) + public TreeNodeLR(ObjectNode objectNode) : base(objectNode) { } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs index ca68132f69..ce09a53ff8 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout /// public class TreeNodeTB : TreeNode { - public TreeNodeTB(NodeControl nodeControl, ObjectNode objectNode) : base(nodeControl, objectNode) + public TreeNodeTB(ObjectNode objectNode) : base(objectNode) { } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs index aa6a586504..a668b6aa7e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs @@ -37,11 +37,12 @@ namespace Debugger.AddIn.Visualizers.Graph { get { return _nodes; } } - + + /* /// /// All edges in the graph. /// - /*public IEnumerable Edges + public IEnumerable Edges { get { diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs index b546c53fcf..99abdfa3ab 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs @@ -51,7 +51,7 @@ namespace Debugger.AddIn.Visualizers.Graph private bool sorted = false; - private List _properties = new List(); + private List properties = new List(); /// /// Properties (either atomic or complex) of the object this node represents. /// @@ -61,10 +61,10 @@ namespace Debugger.AddIn.Visualizers.Graph { if (!sorted) { - _properties.Sort(propertySortComparer); + properties.Sort(propertySortComparer); sorted = true; } - return _properties; + return properties; } } /// @@ -87,7 +87,7 @@ namespace Debugger.AddIn.Visualizers.Graph /// internal void AddAtomicProperty(string name, string value, Expression expression) { - _properties.Add(new ObjectProperty + properties.Add(new ObjectProperty { Name = name, Value = value, Expression = expression, IsAtomic = true, TargetNode = null }); } @@ -96,7 +96,7 @@ namespace Debugger.AddIn.Visualizers.Graph /// internal void AddComplexProperty(string name, string value, Expression expression, ObjectNode targetNode) { - _properties.Add(new ObjectProperty + properties.Add(new ObjectProperty { Name = name, Value = value, Expression = expression, IsAtomic = false, TargetNode = targetNode }); } }