Refreshing diagram with new data

14 posts, 0 answers
  1. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 15 May 2013 Link to this post

    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.
  2. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 15 May 2013 Link to this post

    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.

  3. DevCraft banner
  4. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 15 May 2013 Link to this post

    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.
  5. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 16 Jul 2013 Link to this post

    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.



  6. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 16 Jul 2013 Link to this post

    You need to reset the root node(s) when you update the GraphSource...
  7. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 16 Jul 2013 Link to this post

    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
  8. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 16 Jul 2013 Link to this post

    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.
  9. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 16 Jul 2013 Link to this post

    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.
  10. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 17 Jul 2013 Link to this post

    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.
  11. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 17 Jul 2013 Link to this post

    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.
  12. Barry
    Barry avatar
    90 posts
    Member since:
    Jul 2011

    Posted 17 Jul 2013 Link to this post

    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.
  13. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 17 Jul 2013 Link to this post

    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
  14. Saher
    Saher avatar
    20 posts
    Member since:
    Jul 2013

    Posted 17 Jul 2013 Link to this post

    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
  15. Hristo
    Admin
    Hristo avatar
    352 posts

    Posted 19 Jul 2013 Link to this post

    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 >>
Back to Top
DevCraft banner