Customize OrgChart with Async Web Client datasource

7 posts, 0 answers
  1. Andrew
    Andrew avatar
    8 posts
    Member since:
    Sep 2013

    Posted 23 Jul 2014 Link to this post

    Hello,

    Working on getting the orgchart example working with data pulled from a rest service asynchronously. Within OrgChartViewModel.cs I have changed this.PopulateGraphSources(); to be called asynchronously after retrieving the data and adding the node to this.HeirarchicalDataSource. After the async "this.PopulateGraphSources();" call I then check if this.ViewModesConfigured.

    My nodes are added to the view, but they are stacked on top of one another and the connectors are not drawn correctly. Am I missing a step or code change to get the nodes drawn correctly asynchronously?

    Thanks,
    Andy
  2. Andrew
    Andrew avatar
    8 posts
    Member since:
    Sep 2013

    Posted 23 Jul 2014 in reply to Andrew Link to this post

            private void PopulateWithData()
            {
                string projectName;
    #if WPF
                projectName = "OrgChart_WPF";
    #else
                projectName = "OrgChart_SL";
    #endif
                //var stream = Application.GetResourceStream(new Uri("/" + projectName + ";component/XmlSource/Ceo.xml", UriKind.RelativeOrAbsolute));
                //XElement dataXml = XElement.Load(stream.Stream);
                string serviceUrl = "http://corporateservicestest/HumanResources/v1/Employee/?employeeId={0}&employeeStatusCode=Active&Format=XML";
                string url = string.Format(serviceUrl, ceoEmployeeId);
     
                WebClient client = new WebClient();
     
                client.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
                client.OpenReadAsync(new Uri(url));
                 
            }
            void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                if (e.Error == null)
                {
                    XElement dataXml = XElement.Load(e.Result);
                    foreach (XElement element in dataXml.Descendants("employee"))
                    {
                        Node node = this.CreateNode(element, null);
                        node.Children.AddRange(this.GetSubNodes(element, node));
                        this.HierarchicalDataSource.Add(node);
                    }
     
                }
     
                this.PopulateGraphSources();
     
                if (this.ViewModelsConfigured != null)
                    this.ViewModelsConfigured(this, null);
            }
  3. DevCraft banner
  4. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 28 Jul 2014 Link to this post

    Hi Andrew,

    In the handler of ViewModelsConfigured event, could you please try using the Diagram.LayoutAsync() method and let us know if this solves your scenario ? If not, is it possible for you to send us more from your code or runnable sample that we could better investigate. Thank you in advance for your cooperation.

    Regards,
    Petar Mladenov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  5. Andrew
    Andrew avatar
    8 posts
    Member since:
    Sep 2013

    Posted 28 Jul 2014 in reply to Petar Mladenov Link to this post

    Thanks for the reply - I wasn't able to find a "LayoutAsync()" method within my Diagram assembly.

    Here's a runnable sample of my OrgChartViewModel.cs file to take a look at. Thanks for any assistance!

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Net;
    using System.Threading;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Threading;
    using System.Xml.Linq;
    using Telerik.Windows.Controls;
    using Telerik.Windows.Controls.Diagrams.Extensions.ViewModels;
    using Telerik.Windows.Diagrams.Core;
     
    namespace OrgChart.ViewModels
    {
        public class OrgChartViewModel : ViewModelBase
        {
            private GraphSource graphSource;
            private TreeLayoutType currentTreeLayoutType;
            private ItemDisplayMode currentItemDisplayMode;
            private bool shouldLayoutAfterTemplateChange;
            private bool shouldLayoutAfterExpandCollapse;
            private TreeLayoutViewModel childTreeLayoutViewModel;
            private readonly OrgTreeRouter router = new OrgTreeRouter();
            private double zoomFactor;
            private static double SmallToNormalTemplateThreshHold = 0.75d;
            private static double NormallToLargeTemplateThreshHold = 1.4d;
            private static string ceoEmployeeId = "143470";
     
            public OrgChartViewModel()
            {
                this.GraphSource = new GraphSource();
                this.HierarchicalDataSource = new ObservableCollection<Node>();
                this.PopulateWithData();
                //this.PopulateGraphSources();
                this.ChildRouterViewModel = new OrgRouterViewModel(this.router);
                this.ChildTreeLayoutViewModel = new TreeLayoutViewModel();
                this.CurrentTreeLayoutType = TreeLayoutType.TreeDown;
                this.CurrentItemDisplayMode = ItemDisplayMode.Standard;
                this.BindCommands();
                this.ShouldLayoutAfterTemplateChange = true;
                this.ShouldLayoutAfterExpandCollapse = false;
                this.ZoomFactor = 1.0d;
            }
     
            public event EventHandler<VisibilityChangedEventArgs> NodeVisibilityChanged;
            public event EventHandler CurrentLayoutTypeChanged;
            public event EventHandler CurrentLayoutTypeSettingsChanged;
            public event EventHandler ChildrenExpandedOrCollapsed;
            public event EventHandler ViewModelsConfigured;
     
            public double ZoomFactor
            {
                get { return this.zoomFactor; }
                set
                {
                    if (this.zoomFactor != value)
                    {
                        this.zoomFactor = value;
                        this.OnZoomChanged();
                        this.OnPropertyChanged("ZoomFactor");
                    }
                }
            }      
     
            public ItemDisplayMode CurrentItemDisplayMode
            {
                get { return this.currentItemDisplayMode; }
                set
                {
                    if (this.currentItemDisplayMode != value)
                    {
                        this.currentItemDisplayMode = value;
                        this.OnPropertyChanged("CurrentItemDisplayMode");
                    }
                }
            }
     
            public TreeLayoutType CurrentTreeLayoutType
            {
                get { return currentTreeLayoutType; }
                set
                {
                    this.currentTreeLayoutType = value;
                    this.ChildTreeLayoutViewModel.CurrentTreeLayoutType = value;
                    this.ChildRouterViewModel.CurrentTreeLayoutType = value;
                    this.OnPropertyChanged("CurrentTreeLayoutType");
                    this.OnCurrentLayoutTypeChanged();
                }
            }
     
            public GraphSource GraphSource
            {
                get
                {
                    return this.graphSource;
                }
                set
                {
                    if (this.graphSource != value)
                    {
                        this.graphSource = value;
                        this.OnPropertyChanged("GraphSource");
                    }
                }
            }
     
            public ObservableCollection<Node> HierarchicalDataSource { get; private set; }
     
            public OrgTreeRouter Router { get { return this.router; } }
     
            public DelegateCommand ToggleVisibilityCommand { get; set; }
     
            public TreeLayoutViewModel ChildTreeLayoutViewModel
            {
                get { return this.childTreeLayoutViewModel; }
                protected set
                {
                    if (this.childTreeLayoutViewModel != value)
                    {
                        this.childTreeLayoutViewModel = value;
                        this.OnPropertyChanged("ChildTreeLayoutViewModel");
                    }
                }
            }
     
            public OrgRouterViewModel ChildRouterViewModel { get; protected set; }
     
            public bool ShouldLayoutAfterTemplateChange
            {
                get { return this.shouldLayoutAfterTemplateChange; }
                set
                {
                    if (this.shouldLayoutAfterTemplateChange != value)
                    {
                        this.shouldLayoutAfterTemplateChange = value;
                        this.OnPropertyChanged("ShouldLayoutAfterTemplateChange");
                    }
                }
            }
     
            public bool ShouldLayoutAfterExpandCollapse
            {
                get { return this.shouldLayoutAfterExpandCollapse; }
                set
                {
                    if (this.shouldLayoutAfterExpandCollapse != value)
                    {
                        this.shouldLayoutAfterExpandCollapse = value;
                        this.OnPropertyChanged("ShouldLayoutAfterExpandCollapse");
                    }
                }
            }
     
            public void PopulateGraphSources()
            {
                foreach (var item in this.HierarchicalDataSource)
                {
                    this.GraphSource.PopulateGraphSource(item);
                }
            }
     
            protected bool CanExecuteToggleVisibilityCommand(object o)
            {
                return o != null && (o as Node).Children.Count > 0;
            }
     
            protected void ExecuteToggleVisibilityCommand(object o)
            {
                var node = o as Node;
                var areChildrenCollapsed = node != null && node.AreChildrenCollapsed;
     
                this.ToggleChildrenVisibility(node, areChildrenCollapsed);
                node.AreChildrenCollapsed = !node.AreChildrenCollapsed;
            }
     
            private void BindCommands()
            {
                this.ToggleVisibilityCommand = new DelegateCommand(this.ExecuteToggleVisibilityCommand, this.CanExecuteToggleVisibilityCommand);
            }
     
            private ObservableCollection<HierarchicalNodeViewModel> GetSubNodes(XContainer element, Node parent)
            {
                var nodes = new ObservableCollection<HierarchicalNodeViewModel>();
     
                string projectName;
    #if WPF
                projectName = "OrgChart_WPF";
    #else
                projectName = "OrgChart_SL";
    #endif
     
                var stream = Application.GetResourceStream(new Uri("/" + projectName + ";component/XmlSource/Organization.xml", UriKind.RelativeOrAbsolute));
                XElement dataXml = XElement.Load(stream.Stream);
     
                IEnumerable<XElement> children = from s in dataXml.Descendants("employee")
                               where s.Element("employeeManagerId").Value == parent.ID
                                                     select s;
     
                foreach (XElement subElement in children)
                {
                    Node node = this.CreateNode(subElement, parent);
                    node.Children.AddRange(this.GetSubNodes(subElement, node));
                    nodes.Add(node);
                }
                return nodes;
            }
     
            private Node CreateNode(XElement element, Node parentNode)
            {
                Node node = new Node();
                node.PropertyChanged += this.OnNodePropertyChanged;
                node.FirstName = element.Element("employeeFirstName").Value;
                node.LastName = element.Element("employeeLastName").Value;
                //node.Phone = element.Attribute("Phone").Value;
                node.Email = element.Element("employeeEmailAddress").Value;
                node.ID = element.Element("employeeId").Value;
                node.ReportsTo = element.Element("employeeManagerId").Value;
                node.Address = element.Element("employeeOfficeLocationName").Value;
                node.Path = parentNode == null ? node.FullName : parentNode.Path + "|" + node.FullName;
                node.JobPosition = element.Element("employeeTitle").Value;
     
                return node;
            }
     
            private void OnNodePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "Visibility")
                {
                    if (this.NodeVisibilityChanged != null)
                    {
                        this.NodeVisibilityChanged(sender, new VisibilityChangedEventArgs((sender as Node).Visibility == Visibility.Visible));
                    }
                }
            }
     
            private void PopulateWithData()
            {
     
                string serviceUrl = "http://corporateservicestest/HumanResources/v1/Employee/?employeeId={0}&employeeStatusCode=Active&Format=XML";
                string url = string.Format(serviceUrl, ceoEmployeeId);
     
                WebClient client = new WebClient();
     
                client.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
                client.OpenReadAsync(new Uri(url));
     
     
            }
     
            void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
            {
                if (e.Error == null)
                {
                    XElement dataXml = XElement.Load(e.Result);
                    foreach (XElement element in dataXml.Descendants("employee"))
                    {
                        Node node = this.CreateNode(element, null);
                        node.Children.AddRange(this.GetSubNodes(element, node));
                        this.HierarchicalDataSource.Add(node);
                    }
     
                }
                this.PopulateGraphSources();
     
                if (this.ViewModelsConfigured != null)
                    this.ViewModelsConfigured(this, null);
            }
     
            private void ToggleChildrenVisibility(HierarchicalNodeViewModel node, bool areChildrenVisible)
            {
                foreach (Node subNode in node.Children)
                {
                    var visibility = areChildrenVisible ? Visibility.Visible : Visibility.Collapsed;
                    subNode.Visibility = visibility;
                    subNode.IsSelected = false;
                    this.GraphSource.InternalLinks.Where(link => link.Source == node).ToList()
                        .ForEach(link =>
                        {
                            link.Visibility = visibility;
                            link.IsSelected = false;
                        });
     
                    if (subNode.AreChildrenCollapsed) continue;
     
                    this.ToggleChildrenVisibility(subNode, areChildrenVisible);
                }
                this.OnChildrenExpandedOrCollapsed();
            }
     
            private void OnCurrentLayoutTypeChanged()
            {
                if (this.CurrentLayoutTypeChanged != null)
                {
                    this.CurrentLayoutTypeChanged(this, EventArgs.Empty);
                }
            }
     
            private void OnChildrenExpandedOrCollapsed()
            {
                if (this.ChildrenExpandedOrCollapsed != null)
                {
                    this.ChildrenExpandedOrCollapsed(this, EventArgs.Empty);
                }
            }
     
            private void OnViewModelsConfigured()
            {
                if (this.ViewModelsConfigured != null)
                {
                    //Telerik.Windows.Controls.Diagrams.L
                    this.ViewModelsConfigured(this, EventArgs.Empty);
                }
            }
     
            private void OnZoomChanged()
            {
                ItemDisplayMode newMode;
                if (SmallToNormalTemplateThreshHold < this.ZoomFactor && this.ZoomFactor <= NormallToLargeTemplateThreshHold)
                    newMode = ItemDisplayMode.Standard;
                else if (this.ZoomFactor <= SmallToNormalTemplateThreshHold)
                    newMode = ItemDisplayMode.Small;
                else
                    newMode = ItemDisplayMode.Detailed;
     
                if (this.CurrentItemDisplayMode != newMode)
                    this.ChangeAllShapesDisplayMode(newMode);
            }
     
            private void ChangeAllShapesDisplayMode(ItemDisplayMode newMode)
            {
                this.CurrentItemDisplayMode = newMode;
                foreach (var node in this.GraphSource.InternalItems)
                {
                    node.CurrentDisplayMode = newMode;
                }
            }
        }
     
        public class VisibilityChangedEventArgs : EventArgs
        {
            public VisibilityChangedEventArgs(bool isVisible)
            {
                this.IsVisible = isVisible;
            }
            public bool IsVisible { get; private set; }
        }
    }
  6. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 29 Jul 2014 Link to this post

    Hi Andrew,

    LayoutAsync() method is included in Q3 2013 Release of Telerik UI For WPF/ SIlverlight. We highly encourage you to upgrade to the latest possible version of our controls.
    However, if this is not an option you can try to invoke the Layout function in Dispatcher, for example like so:
    Action action = new Action(() => this.diagram.Layout(...);
     
        this.Dispatcher.BeginInvoke(action);
    I guess you can invoke this in the ViewModelsConfigured event handler. Please let us know if this helps.

    Regards,
    Petar Mladenov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  7. Andrew
    Andrew avatar
    8 posts
    Member since:
    Sep 2013

    Posted 29 Jul 2014 in reply to Petar Mladenov Link to this post

    So I added "this.diagram.LayoutAsync(LayoutType.Tree, null);" to public OrgChartExample() in OrgChartExample.xaml.cs, and now the nodes are no longer stacked on top of eachother, but the tree structure is still not being applied and the shapes are just lined up in 2 rows. What could I be missing?
  8. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 30 Jul 2014 Link to this post

    Hello Andrew,

    You also need to pass settings object of type TreeLayoutSettings as a parameter in the LayoutAsync Demo. Please check out this help article describing how to configure the Layout:
    Diagram Layout
    The main settings to configure are the Root shape of the Layout and the TreeLayoutType.

    Regards,
    Petar Mladenov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top
DevCraft banner