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

Customize OrgChart with Async Web Client datasource

6 Answers 66 Views
Diagram
This is a migrated thread and some comments may be shown as answers.
Andrew
Top achievements
Rank 1
Andrew asked on 23 Jul 2014, 09:42 PM
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

6 Answers, 1 is accepted

Sort by
0
Andrew
Top achievements
Rank 1
answered on 23 Jul 2014, 09:45 PM
        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);
        }
0
Petar Mladenov
Telerik team
answered on 28 Jul 2014, 07:09 AM
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.
 
0
Andrew
Top achievements
Rank 1
answered on 28 Jul 2014, 04:37 PM
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; }
    }
}
0
Petar Mladenov
Telerik team
answered on 29 Jul 2014, 08:24 AM
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.
 
0
Andrew
Top achievements
Rank 1
answered on 29 Jul 2014, 10:08 PM
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?
0
Petar Mladenov
Telerik team
answered on 30 Jul 2014, 08:45 AM
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.
 
Tags
Diagram
Asked by
Andrew
Top achievements
Rank 1
Answers by
Andrew
Top achievements
Rank 1
Petar Mladenov
Telerik team
Share this question
or