This is a migrated thread and some comments may be shown as answers.

Refreshing diagram with new data

17 Answers 342 Views
Diagram
This is a migrated thread and some comments may be shown as answers.
Barry
Top achievements
Rank 1
Barry asked on 15 May 2013, 12:42 PM
I have a diagram that I would like to update based on what the user clicks. Basically I want an organizational chart with two levels... the root level and its children. When a user clicks on a child of the root level then the child become the root and any children that it may have will appear below it.

When the user comes to the page I build the first two levels statically and the diagram loads and looks just fine:

Public Overrides Sub OnNavigatedTo(url As String, parameters As Dictionary(Of String, String))
 
 Dim node1 As New Node With {.Name = "MAGTF", .Visibility = Visibility.Visible}
 Me.RootNode = node1
 Dim node2 As New Node With {.Name = "CE", .Rank = Rank.BrigadierGeneral, .AdvocateCode = AdvocateCode.CE}
 Dim node3 As New Node With {.Name = "GGE", .Rank = Rank.BrigadierGeneral, .AdvocateCode = AdvocateCode.GCE}
 Dim node4 As New Node With {.Name = "ACE", .Rank = Rank.BrigadierGeneral, .AdvocateCode = AdvocateCode.ACE}
 Dim node5 As New Node With {.Name = "LCE", .Rank = Rank.BrigadierGeneral, .AdvocateCode = AdvocateCode.LCE}
 
 node1.Children.Add(node2)
 node1.Children.Add(node3)
 node1.Children.Add(node4)
 node1.Children.Add(node5)
 
 Me.GraphSource.PopulateGraphSource(node1)
 
End Sub

But then when they click on a child node I load the new information from the database and it looks all messed up:

Private Sub RefillNodes(nodes As IEnumerable(Of Unit))
 
   Me.GraphSource.Clear()
 
   Me.RootNode.Children.Clear()
 
   Me.GraphSource.AddNode(RootNode)
 
   For Each Node As Unit In nodes
       'Either this
       Me.RootNode.Children.Add(New Node With {.Name = Node.Name, .Rank = Rank.Captain})
       'Or this
       'Me.GraphSource.AddNode(New Node With {.Name = Node.Name, .Rank = Rank.Captain})
       'Me.GraphSource.AddLink(New Link(RootNode, New Node With {.Name = Node.Name, .Rank = Rank.Captain}))
   Next
 
   Me.GraphSource.PopulateGraphSource(RootNode)
 
End Sub

I can either use PopulateGraphSource or add the nodes and links in the loop, either way it turns out the same.

What am I doing wrong? I add the nodes and the links and then I call Layout - just like I do statically, but the links aren't connected to the nodes and the nodes are laid out all funky.

Attached is an example of the before and after I click on a child node.

17 Answers, 1 is accepted

Sort by
0
Barry
Top achievements
Rank 1
answered on 15 May 2013, 02:11 PM
I figured out what I was doing wrong, I was trying to add a new node and then add a new link with a new node instead of the node that I just added.

This code works:

Dim newNode As Node
 
For Each Node As Unit In nodes
 
   newNode = New Node With {.Name = Node.Name, .Rank = Rank.Major}
   Me.GraphSource.AddNode(newNode)
   Me.GraphSource.AddLink(New Link(Me.RootNode, newNode))
 
Next

But oddly when I add multiple links the first link always ends up above the root... it only happens when I have more than one child.

0
Barry
Top achievements
Rank 1
answered on 15 May 2013, 02:20 PM
I figured this one out too... I thought I saw a post about this and I was right.

All I had to do was reset the layout root.
0
Saher
Top achievements
Rank 1
answered on 16 Jul 2013, 09:53 PM
Hello,

I am facing a similar issue where my graph is tree layout and looks fine initially. However, if I choose to change GraphSource upon user input/ clicks using PopulateGraphSource like in the OrgChart example, I get all the nodes stacked on top of each other with no links and all in corner.

I tried resetting graphSource by creating a new one  
this.graphSource = new GraphSource();

I also tried to use the Clear method for GraphSource. Neither did solve the problem, I keep having the same issue.



0
Barry
Top achievements
Rank 1
answered on 16 Jul 2013, 10:16 PM
You need to reset the root node(s) when you update the GraphSource...
0
Saher
Top achievements
Rank 1
answered on 16 Jul 2013, 10:28 PM
what does that mean?
How do I reset the Node object?

I am using
ObservableCollection<Node> hierarchicalDataSource;
to fill up my GraphSource object.

All I do is create a new one and then call
PopulateGraphSource();
method.

thanks
0
Barry
Top achievements
Rank 1
answered on 16 Jul 2013, 10:38 PM
The PopulateGraphSource() is crap, you're better off adding nodes and links manually and then resetting the root node(s).

I don't know what is wrong with that method, but I could never get it to re-populate using that and not mess it up.
0
Saher
Top achievements
Rank 1
answered on 16 Jul 2013, 11:09 PM
but this doesn't make sense:

PopulateGraphSource basically adds nodes and links recursively:
 
public void PopulateGraphSource(Node node)
        {           
          this.AddNode(node);
          foreach (Node subNode in node.Children){
                   Link link = new Link(node, subNode);
                   this.AddLink(link);
                   this.PopulateGraphSource(subNode);
          }   
}

Thanks for your responses, I appreciate it.
0
Barry
Top achievements
Rank 1
answered on 17 Jul 2013, 12:29 PM
Here's how I do it.

You have to make two properties:
private Telerik.Windows.Diagrams.Core.TreeLayoutSettings currentLayoutSettingsValue =
new Telerik.Windows.Diagrams.Core.TreeLayoutSettings();
 
public Telerik.Windows.Diagrams.Core.TreeLayoutSettings CurrentLayoutSettings {
    get { return currentLayoutSettingsValue; }
    set {       currentLayoutSettingsValue = value; }
}
private TreeLayout TreeLayout;

Lets say that your RadDiagram is called OrgChart...

When you update your GraphSource, you need to reset the layout like this:

CurrentLayoutSettings.Roots.Clear();
 
foreach (var node in hierarchicalDataSource) {
    if (node.Children.Count > 0) {
    CurrentLayoutSettings.Roots.Add(OrgChart.Shapes.Where(s => s.Content.Equals(node)).FirstOrDefault);
    }
}
 
TreeLayout.Layout(OrgChart, CurrentLayoutSettings);

So you need to do this stuff after you re-populate your GraphSource. You can either do that using PopulateGraphSource (which may not work) or do it manually. Like I said, I do it manually.

My C# code may not be correct... I primarily use VB.
0
Saher
Top achievements
Rank 1
answered on 17 Jul 2013, 05:45 PM
Hi Barry,

I appreciate your reply. Thank You.

Unfortunately, this did not work. I get the nodes but everything looks messed up as if there is no root node, the links look weird.

again, I am not sure I understand difference between manual and PopulateGraphSource,  PopulateGraphSource I override as follows:

 
public void PopulateGraphSource(Node node)
        {
            this.AddNode(node);
            foreach (Node subNode in node.Children)
            {
                Link link = new Link(node, subNode);
                this.AddLink(link);
                this.PopulateGraphSource(subNode);
            }
        }

Isn't that what you will manually do?

I tried calling these before graph re-population:

this.GraphSource.Clear();
this.GraphSource.InternalItems.Clear();
this.GraphSource.InternalLinks.Clear();
but with same result. What other options I can try?
why creating a new GraphSource object doesn't solve it? This is so confusing.
0
Barry
Top achievements
Rank 1
answered on 17 Jul 2013, 05:53 PM
Can you post your code of what you're doing when you re-populate the GraphSource?

There really is no difference between PopulateGraphSource and doing it manually. I just had issues with it when I first tried it, like you are, and gave up on using it.
0
Saher
Top achievements
Rank 1
answered on 17 Jul 2013, 06:21 PM
the click event does the following:

this.RelTreeDataSource = getData(selection); //this returns an ObservableCollection<Node> object
this.PopulateGraphSources();
PopulateGraphSources() defined:

private void PopulateGraphSources()
        {
             
            foreach (var item in this.RelTreeDataSource)
            {
                this.GraphSource.PopulateGraphSource(item);
            }
             
        }
public void PopulateGraphSource(Node node)
        {
            this.AddNode(node);
            foreach (Node subNode in node.Children)
            {
                Link link = new Link(node, subNode);
                this.AddLink(link);
                this.PopulateGraphSource(subNode);
            }
        }

Then I apply the code you suggested:

ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Clear();
            foreach (var node in RelTreeDataSource)
            {
                if (node.Children.Count > 0)
                {
                    ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Add(diagram.Shapes.Where(s => s.Content.Equals(node)).FirstOrDefault());
                }
            }                             
                         
 
            OnLoaded(sender, e);
            this.diagram.RoutingService.Router = this.Router;
             Dispatcher.BeginInvoke(() => this.treeLayout.Layout(this.diagram, this.ChildTreeLayoutViewModel.CurrentLayoutSettings));

The OnLoaded function defined:

foreach (var item in this.RelTreeDataSource)
           {
               RadDiagramShape shape = this.diagram.ContainerGenerator.ContainerFromItem(item) as RadDiagramShape;
               this.ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Add(shape);
           }
           this.diagram.Layout(LayoutType.Tree);
 
//suspend auto update
           this.diagram.Connections.ForEach(x => RadDiagramConnection.SetIsAutoUpdateSuppressed((RadDiagramConnection)x, true));
           this.CurrentTreeLayoutType = TreeLayoutType.TreeDown;
            
           this.treeLayout.Layout(this.diagram, ChildTreeLayoutViewModel.CurrentLayoutSettings);
            
 
           //undo suspend
           this.diagram.Connections.ForEach(x => RadDiagramConnection.SetIsAutoUpdateSuppressed((RadDiagramConnection)x, false));
           this.diagram.Connections.ForEach(x => x.Update());
 
           if(shouldAutoFit)
               this.diagram.AutoFit(new Thickness(10), false);
            
 
           Dispatcher.BeginInvoke(() => this.treeLayout.Layout(this.diagram, ChildTreeLayoutViewModel.CurrentLayoutSettings));


Thanks
0
Saher
Top achievements
Rank 1
answered on 17 Jul 2013, 06:27 PM
the click event does the following:

this.RelTreeDataSource = getData(selection); //this returns an ObservableCollection<Node> object
this.PopulateGraphSources();
PopulateGraphSources() defined:

private void PopulateGraphSources()
        {
             
            foreach (var item in this.RelTreeDataSource)
            {
                this.GraphSource.PopulateGraphSource(item);
            }
             
        }
public void PopulateGraphSource(Node node)
        {
            this.AddNode(node);
            foreach (Node subNode in node.Children)
            {
                Link link = new Link(node, subNode);
                this.AddLink(link);
                this.PopulateGraphSource(subNode);
            }
        }

Then I apply the code you suggested:

ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Clear();
            foreach (var node in RelTreeDataSource)
            {
                if (node.Children.Count > 0)
                {
                    ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Add(diagram.Shapes.Where(s => s.Content.Equals(node)).FirstOrDefault());
                }
            }                             
                         
 
            OnLoaded(sender, e);
            this.diagram.RoutingService.Router = this.Router;
             Dispatcher.BeginInvoke(() => this.treeLayout.Layout(this.diagram, this.ChildTreeLayoutViewModel.CurrentLayoutSettings));

The OnLoaded function defined:

foreach (var item in this.RelTreeDataSource)
           {
               RadDiagramShape shape = this.diagram.ContainerGenerator.ContainerFromItem(item) as RadDiagramShape;
               this.ChildTreeLayoutViewModel.CurrentLayoutSettings.Roots.Add(shape);
           }
           this.diagram.Layout(LayoutType.Tree);
 
//suspend auto update
           this.diagram.Connections.ForEach(x => RadDiagramConnection.SetIsAutoUpdateSuppressed((RadDiagramConnection)x, true));
           this.CurrentTreeLayoutType = TreeLayoutType.TreeDown;
            
           this.treeLayout.Layout(this.diagram, ChildTreeLayoutViewModel.CurrentLayoutSettings);
            
 
           //undo suspend
           this.diagram.Connections.ForEach(x => RadDiagramConnection.SetIsAutoUpdateSuppressed((RadDiagramConnection)x, false));
           this.diagram.Connections.ForEach(x => x.Update());
 
           if(shouldAutoFit)
               this.diagram.AutoFit(new Thickness(10), false);
            
 
           Dispatcher.BeginInvoke(() => this.treeLayout.Layout(this.diagram, ChildTreeLayoutViewModel.CurrentLayoutSettings));


Thanks
0
Hristo
Telerik team
answered on 19 Jul 2013, 01:35 PM
Hi Saher,

As I have noted in the other forum post you created  here, the best way to proceed would be to investigate your project in order to find the root cause for your issues. This would be the fastest way to assist you in finding a solution.

Also, as soon as we solve the issue in the other thread, I will make sure to update this forum to reflect our findings.

Regards,
Hristo
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Alvise
Top achievements
Rank 1
answered on 13 Mar 2017, 02:09 PM

Hi,

Can you provide the solution to Saher's issue?

Thanks!

0
Martin Ivanov
Telerik team
answered on 16 Mar 2017, 09:06 AM
Hello guys,

The behavior with the wrong layout and the connections that are not properly linked, comes from the fact that the order of adding links and connections in the GraphSource is not set up as it should be. Basically, all nodes should be added in the graph source before the links that connect them. Otherwise, the connection could be missed when the visual elements are created (RadDiagramShape and RadDiagramConnection).

So, in this specific case (the OrgChart example), the issue comes from the PopulateGraphSource() method. In order to resolve this you can switch the lines of code in the "foreach" loop. Here is an example:
public void PopulateGraphSource(Node node)
{
    this.AddNode(node);
    foreach (Node subNode in node.Children)
    {          
        this.PopulateGraphSource(subNode);
        Link link = new Link(node, subNode);
        this.AddLink(link);    
    }
}

I hope this helps.

Regards,
Martin
Telerik by Progress
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Luc
Top achievements
Rank 1
answered on 08 Jun 2017, 12:11 PM

Tnx Martin!

Adapting PopulateGraphSource() by putting the recursive call before the link creation code solved a similar issue for me. I am now able to repopulate the diagram ... . Have been studying the component for several hours, not suspecting the demo code ;-(

Regards,

Luc Vervoort

0
Martin Ivanov
Telerik team
answered on 09 Jun 2017, 09:21 AM
Hi Luc,

I am glad to hear that the given solution helps.

Regards,
Martin Ivanov
Progress Telerik
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Tags
Diagram
Asked by
Barry
Top achievements
Rank 1
Answers by
Barry
Top achievements
Rank 1
Saher
Top achievements
Rank 1
Hristo
Telerik team
Alvise
Top achievements
Rank 1
Martin Ivanov
Telerik team
Luc
Top achievements
Rank 1
Share this question
or