A few issues with sub graphs


I am experiencing a few issues with using sub graphs, I have broken them down and numbered them for easy reference.

1. You may remember that I have implemented my own approach to collapsing and expanding a node’s subtree. This was because our diagram ‘flow direction’ was the reverse of what the diagram supports. This works fine until I start using sub graphs. When I expand my sub graph (using g.IsExpandedSubGraph = !g.IsExpandedSubGraph; taken from your grouping example) it expands my whole tree (within the sub graph) regardless of whether it was expanded before or not.

2. We will have links between nodes in different sub graphs. These links don’t seem to obey my rules set for my link template. Outside of a sub graph my links happily avoid my nodes. Inside a sub graph this doesn’t seem to happen. Do I need a separate linking tool for a sub graph?

3. The visibility of links between nodes in different sub graphs seems to be a bit random. If we have two sub graphs with a load of nodes in and a connection between two nodes within different sub graphs, with both sub graphs expanded the link is shown. Collapse a sub graph and the link disappears. Collapse the second sub graph and the link stays hidden, however expand either of the sub-graphs and the link re-appears. This seems to be a bug as it is inconsistent. For our solution we would like the links to persist regardless of the state of the sub graphs.

  1. Expanding/collapsing subgraphs ought to be completely independent of expanding/collapsing trees. So I wouldn’t think that expanding a subgraph should expand or collapse any tree structure of the subgraph member nodes and links. It should just make them visible.

To take the Grouping sample as an example, collapsing or expanding subgraphs doesn’t collapse or expand any tree-like structure of the member nodes and links. (Although the subgraphs aren’t actually tree-structured.) It just changes the visibility of the member nodes and links.

But maybe I don’t understand what you are doing and what you want.

  1. I’ll investigate this. It ought to be the case that “AvoidsNodes” links within a subgraph will avoid other nodes within that subgraph, as one would expect.

  2. Are you using the latest DLL: latest DLLs?

We did fix a bug relating to the visibility of links between/into subgraphs.

Hi Walter,

I’ll have a play with the latest dll and see what it fixes, thanks. As for the first issue, when I collapse my sub-tree I’m setting the visibility of my child nodes to false. I presume when I expand a sub graph it is setting the visibility back to true?

I can’t seem to run with that dll. Is it because I’m still running the evaluation version? We have ordered the full version so I can wait to try with that when it arrives…

Edit: I’ve got it working now.

Hi, I think you may have unwittingly introduced a new bug in the latest code base. The links between my sub-graphs now work fine but when I hide my child nodes within a sub graph, the links stay visible. It looks as though they are now linking from the sub-graph though, is this by design?

If I correctly understand the scenario you are describing, yes, that is by design. It’s what most people expect for most applications.

Hmmm, it seems odd to me as it is inconsistent with the behaviour outside of a sub graph. Let me try to clarify the issue. On my parent nodes I have the ability to hide any child nodes (the parent child relationship is the inverse of yours, hence writing my own collapse/expand functionality). Outside of a sub graph, hiding the child nodes also hides the links. When I perform the same task in a sub graph, the links stay visible but come from the sub graph instead of the original node.

EDIT: I’m talking about links between nodes within the same sub graph, I think this maybe where the confusion is.

Well, I’m confused. I think a few small screen shots would help explain things.

Ok, I’ve done a few screen shots that will hopefully help explain the issue.

This is our sub graph with all our child nodes (of the parent node, not the sub graph) expanded.

Now this is what happens when I collapse all the child nodes.

Like I said, this is new behaviour in the latest dll version as it didn’t happen before and I have confirmed this by running the same code in the earlier version.

While we’re at it, here’s a screen shot of the links overlapping nodes within a sub graph.

“Tree collapsing” and “tree expanding” occur on a “tree parent” node. It seems to me that you are only hiding some of the “tree children” of “Parent 2”, because “Parent 1” is still visible.

So I think GoXam’s concept of tree collapsing/expanding is different from what you are expecting. What you are doing is quite reasonable, but it just isn’t what we designed and implemented.

I would implement what you are doing in the following manner:

foreach (Node mem in subgraph.MemberNodes) {
if (IsChildData(mem)) {
mem.Visible = false;
foreach (Link l in mem.ConnectedLinks) l.Visible = false;

Now I don’t know what your graph connectivity might be, but showing child data nodes might be a bit trickier, because in order to make a Link Visible again, you need to make sure that both ends of the Link are now supposed to be Visible. It might be easiest to first make all of the desired Nodes Visible, and then run through all of the Links connecting with all of those now-visible Nodes.

Cheers Walter, I should have explained that even though (in the example above) Parent 1 is technically a child of Parent 2, we would still like all Parent nodes to be visible.

I think I gather what you’re suggesting is that I need to hide all the links as well as the nodes when I collapse my tree? The question is, why does this work fine when outside of a sub graph?

Since I don’t know what you’ve implemented, I can’t say.

I suggest you try to implement what you want without depending on the Node.CollapseTree/ExpandTree methods or the Node.IsExpandedTree property or the attached properties IsTreeExpanded and WasTreeExpanded.

I’m not using any of the collapse/expand tree methods since I’ve written my own custom implementation of this that simply sets the visibility of nodes to false that I wish to ‘collapse’.

I must admit I’m a bit confused as to which issue we’re trying to resolve here. I will try to mock up a simple example that illustrates the various issues that we have, I will then post up this source code.

I think I may have worked out what’s going on. In your fix for the latest version, I’m guessing you now persist links in sub graphs (I’m not sure of the correct terminology).

Anyway, I have included the code for a very simplified version of what I’m doing. Right-click the blue node to toggle the child nodes and you will see what I mean. You’ll also see what happens when you collapse and expand the sub graph when the children are hidden, they re-appear.

I presume then, as you suggested earlier that I’m going to have to hide the links as well when I perform my node hiding.

using System; <br />using System.Collections.Generic; <br />using System.Collections.ObjectModel; <br />using System.Linq; <br />using System.Text; <br />using System.Windows; <br />using System.Windows.Controls; <br />using System.Windows.Data; <br />using System.Windows.Documents; <br />using System.Windows.Input; <br />using System.Windows.Media; <br />using System.Windows.Media.Imaging; <br />using System.Windows.Shapes; <br />using Northwoods.GoXam; <br />using Northwoods.GoXam.Layout; <br />using Northwoods.GoXam.Model; <br /> <br />namespace WpfApplication1 <br />{ <br /> /// <summary> <br /> /// Interaction logic for TestBench.xaml <br /> /// </summary> <br /> public partial class TestBench : UserControl <br /> { <br /> public TestBench() <br /> { <br /> InitializeComponent(); <br /> <br /> var model = new GraphLinksModel<MyData, string, string, MyLink>(); <br /> <br /> var subgraph = new MyData() { IsSubGraph = true, Name = "Subgraph 1" }; <br /> var parent = new MyData() { Name = "Node 1", SubGraphKey = subgraph.Key, Colour = "Blue" }; <br /> var child1 = new MyData() { Name = "Node 2", SubGraphKey = subgraph.Key, Colour = "Red" }; <br /> var child2 = new MyData() { Name = "Node 3", SubGraphKey = subgraph.Key, Colour = "Red" }; <br /> <br /> model.NodesSource = new ObservableCollection<MyData>() { subgraph, parent, child1, child2 }; <br /> <br /> model.LinksSource = new ObservableCollection<MyLink>() { <br /> new MyLink(){From = child1.Key, FromPort="0", To = parent.Key, ToPort="0"}, <br /> new MyLink(){From = child2.Key, FromPort="0", To = parent.Key, ToPort="0"} <br /> }; <br /> <br /> myDiagram.Model = model; <br /> myDiagram.Model.Modifiable = true; <br /> } <br /> <br /> private void CollapseExpandButton_Click(object sender, RoutedEventArgs e) <br /> { <br /> // the Button is in the visual tree of a Node <br /> Button button = (Button)sender; <br /> Group g = Part.FindAncestor<Group>(button); <br /> if (g != null) <br /> { <br /> // always make changes within a transaction <br /> myDiagram.StartTransaction("CollapseExpand"); <br /> // toggle whether this node is expanded or collapsed <br /> g.IsExpandedSubGraph = !g.IsExpandedSubGraph; <br /> myDiagram.CommitTransaction("CollapseExpand"); <br /> } <br /> } <br /> <br /> private void toggleTreeMenuItem_Click(object sender, RoutedEventArgs e) <br /> { <br /> MenuItem mi = sender as MenuItem; <br /> if (mi != null) <br /> { <br /> ContextMenu cm = mi.CommandParameter as ContextMenu; <br /> if (cm != null) <br /> { <br /> Node n = Part.FindAncestor<Node>(cm.PlacementTarget as UIElement); <br /> if (n != null) <br /> { <br /> MyData data = n.Data as MyData; <br /> <br /> // always make changes within a transaction <br /> myDiagram.StartTransaction("CollapseExpand"); <br /> <br /> if (data.IsExpanded) <br /> { <br /> CollapseTree(n); <br /> data.IsExpanded = false; <br /> } <br /> else <br /> { <br /> ExpandTree(n); <br /> data.IsExpanded = true; <br /> } <br /> <br /> myDiagram.CommitTransaction("CollapseExpand"); <br /> } <br /> } <br /> } <br /> } <br /> <br /> private void CollapseTree(Node node) <br /> { <br /> foreach (Node n in node.NodesInto) <br /> { <br /> if (n != node) <br /> { <br /> CollapseTree(n); <br /> n.Visible = false; <br /> myDiagram.LayoutDiagram(); <br /> } <br /> } <br /> } <br /> <br /> <br /> private void ExpandTree(Node parentNode) <br /> { <br /> <br /> foreach (Node n in parentNode.NodesInto) <br /> { <br /> if (n != parentNode) <br /> { <br /> ExpandTree(n); <br /> n.Visible = true; <br /> myDiagram.LayoutDiagram(); <br /> } <br /> } <br /> } <br /> } <br /> <br /> <br /> public class MyData : GraphLinksModelNodeData<string> { <br /> public string Name { get; set; } <br /> public string Colour { get; set; } <br /> public bool IsExpanded { get; set; } <br /> <br /> public MyData() <br /> { <br /> Key = Guid.NewGuid().ToString(); <br /> } <br /> } <br /> <br /> public class MyLink : GraphLinksModelLinkData<string, string> { } <br />}

<UserControl x:Class="WpfApplication1.TestBench" <br /> xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <br /> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" <br /> xmlns:go="http://schemas.nwoods.com/GoXam" <br /> xmlns:local="clr-namespace:WpfApplication1"> <br /> <UserControl.Resources> <br /> <!-- show either a "+" or a "-" as the Button content --> <br /> <go:BooleanStringConverter x:Key="theButtonConverter" TrueString="-" FalseString="+" /> <br /> <br /> <DataTemplate x:Key="NodeTemplate"> <br /> <go:NodePanel Sizing="Auto" go:Part.SelectionAdorned="True"> <br /> <go:NodeShape go:NodePanel.Figure="Ellipse" Fill="{Binding Path=Data.Colour}" /> <br /> <TextBlock Text="{Binding Path=Data.Name}" Foreground="White"/> <br /> <go:NodePanel.ContextMenu> <br /> <ContextMenu> <br /> <MenuItem Name="toggleTree" Header="Toggle Tree" Click="toggleTreeMenuItem_Click" <br /> CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Parent}"/> <br /> </ContextMenu> <br /> </go:NodePanel.ContextMenu> <br /> </go:NodePanel> <br /> </DataTemplate> <br /> <br /> <DataTemplate x:Key="GroupTemplate"> <br /> <Border CornerRadius="5" BorderThickness="2" Background="Transparent" <br /> BorderBrush="Green" <br /> go:Part.SelectionAdorned="True" <br /> go:Node.LocationElementName="myGroupPanel" <br /> go:Group.IsSubGraphExpanded="False"> <br /> <StackPanel> <br /> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <br /> <Button x:Name="myCollapseExpandButton" Click="CollapseExpandButton_Click" <br /> Content="{Binding Path=Group.IsExpandedSubGraph, Converter={StaticResource theButtonConverter}}" <br /> Width="20" Margin="0 0 5 0"/> <br /> <TextBlock Text="{Binding Path=Data.Name}" FontWeight="Bold"/> <br /> </StackPanel> <br /> <go:GroupPanel x:Name="myGroupPanel" Padding="5" /> <br /> </StackPanel> <br /> <go:Group.Layout> <br /> <go:LayeredDigraphLayout Direction="90" Conditions="Standard GroupSizeChanged" /> <br /> </go:Group.Layout> <br /> </Border> <br /> </DataTemplate> <br /> </UserControl.Resources> <br /> <br /> <Grid> <br /> <go:Diagram x:Name="myDiagram" Padding="10" <br /> HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" <br /> NodeTemplate="{StaticResource NodeTemplate}" <br /> GroupTemplate="{StaticResource GroupTemplate}"> <br /> <go:Diagram.Layout> <br /> <go:ForceDirectedLayout Conditions="Standard GroupSizeChanged" /> <br /> </go:Diagram.Layout> <br /> </go:Diagram> <br /> </Grid> <br /></UserControl> <br />

I’m now setting the link visibility and this works fine. As for the issue of expanding a group showing my hidden child items, is there a way of enumerating all the nodes contained in a sub-graph. Obviously I can go through every node in my diagram to see if it has the required SubGraphKey but this seems a bit excessive.

You can get all of the immediate child nodes of a group with Group.MemberNodes. (There is also Group.MemberLinks.)

At the model level, you can call IGroupsModel.GetMemberNodesForGroup. That’s what Group.MemberNodes calls, and then it applies PartManager.FindNodeForData on each node data of that collection to get the Nodes.

Almost all navigation in the diagram is actually done by querying the model.

Thanks Walter. I’ve implemented something using a LINQ query on the Diagram.Nodes collection, it seems to work well but I wonder what the performance will be like when I scale up the application. I’ll bare in mind your solution to see if it improves performance.

Walter, there definitely seems to be an issue with the routing of links within sub graphs. See the last of the three pictures in the posts above.

I think a link connecting two member nodes of a subgraph should route as one would expect.

It’s possible that a link from outside a subgraph won’t route around nodes within the subgraph that contains the node that the link is connected with. I suspect there’s no easy solution for that at this time.