WPF 拓扑图 Topographies

MainWindow.xaml

<Window x:Class="Topographies.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="900" Visibility="Visible">
    <ScrollViewer x:Name="MyScoller"  Background="White" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"  >
        <!---->
        <Canvas  Name="board" Width="{Binding ElementName=MyCanvas,Path=Width}" Height="{Binding ElementName=MyCanvas,Path=Height}" >
            <Canvas  Name="MyCanvas" MouseLeftButtonDown="ele_MouseLeftButtonDown" 
MouseLeftButtonUp="ele_MouseLeftButtonUp" MouseMove="ele_MouseMove"></Canvas>
        </Canvas>
    </ScrollViewer>      

</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml;


namespace Topographies
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public List<Person> persons = new List<Person>();
        public double totalWidth;
        public double totalHight;
        public double buttonWidth;
        public double buttonHeight;
        public double plusButtonWidth;
        public double plusButtonHeight;
        public double levelHight;
        public double minHorizontalSpace;
        public double minVerticalSpace;
        public double fontSize;
        public SolidColorBrush LinesStroke;
        public double LinesStrokeThickness;
        public DispatcherTimer _doubleClickTimer;
        public double drawingScale = 1;
        public MainWindow()
        {
            InitializeComponent();
            LoadXMLFile();
        }
        private void Rescale()
        {
            MyCanvas.Children.Clear();
            buttonWidth = 150 * drawingScale;
            buttonHeight = 80 * drawingScale;
            minHorizontalSpace = 10 * drawingScale;
            minVerticalSpace = 10 * drawingScale;
            plusButtonWidth = 12 * drawingScale;
            plusButtonHeight = 12 * drawingScale;
            fontSize = 10 * drawingScale;
            LinesStrokeThickness = 1 * drawingScale;
            levelHight = buttonHeight + minVerticalSpace * 2;
            Refresh();
        }


        private void Refresh()
        {
            MyCanvas.Width = buttonWidth;
            MyCanvas.Height = buttonHeight;
            totalWidth = MyCanvas.Width;
            totalHight = MyCanvas.Height;
            persons[0].MinChildWidth = buttonWidth + minHorizontalSpace;
            persons[0].StartX = 0;
            persons[0].X = persons[0].MinChildWidth / 2;
            SetLevel(persons[0], 1);
            CalculateWidth(persons[0]);
            CalculateX(persons[0]);
            DrawNode(persons[0]);
        }
        #region Load XML
        private void LoadXMLFile()
        {
            XmlDocument doc = new XmlDocument();
            string currentdir = Directory.GetCurrentDirectory();//获取当前路径




            string targetXmlUrl =
            @"../../OrgChart_Data.xml";
            doc.Load(targetXmlUrl);    //加载Xml文件  
            XmlElement rootElem = doc.DocumentElement;   //获取根节点  
            if (rootElem != null)
            {
                Person firstNode = Person.GetPerson("OrgChartRootNode", "My Organization", "", "", "", "", "");
                firstNode.MinChildWidth = totalWidth;
                persons.Add(firstNode);
                XmlNodeList personNodes = rootElem.GetElementsByTagName("Person"); //获取person子节点集合  
                foreach (XmlNode node in personNodes)
                {
                    XmlNodeList attributes = ((XmlElement) node).ChildNodes;   //获取name属性值  
                    Person person = new Person();
                    foreach (XmlNode attribute in attributes)
                    {
                        XmlElement attElement = (XmlElement) attribute;
                        if (attElement.Name == "ID")
                        {
                            string Id = attElement.InnerText;
                            person.ID = Id;
                        }
                        if (attElement.Name == "Name")
                        {
                            string name = attElement.InnerText;
                            person.Name = name;
                        }
                        if (attElement.Name == "Title")
                        {
                            string title = attElement.InnerText;
                            person.Title = title;
                        }
                        if (attElement.Name == "Department")
                        {
                            string department = attElement.InnerText;
                            person.Department = department;
                        }
                        if (attElement.Name == "Extension")
                        {
                            string etension = attElement.InnerText;
                            person.Extension = etension;
                        }
                        if (attElement.Name == "Email")
                        {
                            string email = attElement.InnerText;
                            person.Email = email;
                        }
                        if (attElement.Name == "ManagerID")
                        {
                            string managerID = attElement.InnerText;
                            person.ManagerID = managerID;
                        }
                        
                    }
                    if (string.IsNullOrEmpty(person.ManagerID))
                    {
                        person.ManagerID = "OrgChartRootNode";
                    }
                    persons.Add(person);
                }
                Rescale();
            }
        }


      
        #endregion


        #region Calculate Values
        private void SetLevel(Person parent, int level)
        {
            // Set the node level
            parent.Level = level;


            // Calculate the total height based on the number of levels
            if (totalHight < levelHight * (level + 2))
            {
                totalHight = levelHight * (level + 2);
                MyCanvas.Height = totalHight;
            }


            // Select the closed items under this parent
            var resultN = from n in persons
                          where n.ManagerID == parent.ID && n.Opened == false
                          select n;


            // Get the closed nodes number
            parent.HiddenSubNodes = resultN.Count();


            // Select the opend nodes under this parent
            var result = from n in persons
                         where n.ManagerID == parent.ID && n.Opened == true
                         select n;


            Person[] nodes = result.ToArray();


            // Get the Opend nodes number
            parent.SubNodes = nodes.Length;


            // Call the child nodes
            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i].NodeOrder = i + 1;
                nodes[i].MinChildWidth = buttonWidth + minHorizontalSpace;
                SetLevel(nodes[i], parent.Level + 1);
            }
        }


        private void CalculateWidth(Person parent)
        {
            if (parent.SubNodes > 0)
            {
                var result = from n in persons
                             where n.ManagerID == parent.ID && n.Opened == true
                             orderby n.NodeOrder
                             select n;


                Person[] nodes = result.ToArray();
                double width = 0;


                for (int i = 0; i < nodes.Length; i++)
                {
                    // calculate the width of the child before adding it to the parent
                    CalculateWidth(nodes[i]);


                    // calculate the new width
                    width = width + nodes[i].MinChildWidth;
                }


                if (width > parent.MinChildWidth)
                {
                    parent.MinChildWidth = width;
                    if (MyCanvas.Width < width)
                    {
                        MyCanvas.Width = width;
                        //totalWidth = width;
                    }
                }
            }
        }


        private void CalculateX(Person parent)
        {
            if (parent.SubNodes > 0)
            {
                var result = from n in persons
                             where n.ManagerID == parent.ID && n.Opened == true
                             orderby n.NodeOrder
                             select n;


                Person[] nodes = result.ToArray();


                // Calculate the startX for each node
                double start = parent.StartX;
                for (int i = 0; i < nodes.Length; i++)
                {
                    nodes[i].StartX = start;
                    nodes[i].X = nodes[i].StartX + nodes[i].MinChildWidth / 2;
                    CalculateX(nodes[i]);
                    start = start + nodes[i].MinChildWidth;
                }


                // realign the parent node to the middle of the child nodes
                if (nodes.Length > 1)
                {
                    parent.X = (nodes[0].X + nodes[nodes.Length - 1].X) / 2;
                }
                else // root element
                {
                    parent.X = nodes[0].X;
                }
            }
        }
        #endregion


        #region Draw
        private void DrawNode(Person parent)
        {
            // Check if the current node is the parent node or not
            if (parent.ManagerID == "")
            {
                AddBox(MyCanvas, parent.X, parent.Level * levelHight, null, parent.ID, parent.Name, parent.Title, parent.Department, parent.Extension, false, true, parent.HiddenSubNodes > 0);
            }


            // Get the child nodes
            var results = from n in persons
                          where n.ManagerID == parent.ID && n.Opened == true
                          select n;


            foreach (Person p in results)
            {
                AddBox(MyCanvas, p.X, p.Level * levelHight, parent.X, p.ID, p.Name, p.Title, p.Department, p.Extension, true, p.SubNodes > 0, p.HiddenSubNodes > 0);
                DrawNode(p);
            }
        }


        public void DrawLine(Canvas canvas, double x1, double y1, double x2, double y2)
        {
            Line line = new Line();
            line.X1 = x1;
            line.Y1 = y1;
            line.X2 = x2;
            line.Y2 = y2;
            line.Stroke = Util.GetColorFromHex("#FF6495ed");
            line.StrokeThickness = LinesStrokeThickness;
            canvas.Children.Add(line);
        }


        public void AddBox(Canvas canvas, double x, double y, double? parentX, string ID, string name, string title, string department, string extension, bool root, bool subNodes, bool hiddenSubNodes)
        {
            NodeBox nb = new NodeBox(drawingScale);
            //nb.Name = ID;
            nb.EmployeeName = name;
            nb.Title = title;
            nb.Department = department;
            nb.Extension = extension;
            nb.Width = buttonWidth;
            nb.Height = buttonHeight;
            nb.SetValue(Canvas.LeftProperty, x - nb.Width / 2);
            nb.Target = "plus" + ID;
            nb.SetValue(Canvas.TopProperty, y);


            nb.ButtonBase.Click += btn_Click;


            // handle the double click actions
            _doubleClickTimer = new DispatcherTimer();
            _doubleClickTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
            _doubleClickTimer.Tick += new EventHandler(delegate { _doubleClickTimer.Stop(); });
            nb.MouseLeftButtonDown += new MouseButtonEventHandler(delegate
            {
                if (_doubleClickTimer.IsEnabled)
                {
                    _doubleClickTimer.Stop();
                    btnClicked(ID);
                }
                else
                {
                    _doubleClickTimer.Start();
                }
            });


            canvas.Children.Add(nb);


            // The line above the box
            if (root)
                DrawLine(canvas, x-3, y - minVerticalSpace, x-3, y);




            // Draw the horizontal line to the parent
            if (parentX != null)
                DrawLine(canvas, x-3, y - minVerticalSpace, Convert.ToDouble(parentX-3), y - minVerticalSpace);




            // Draw the line under the box
    
            nb.ButtonBase.IsChecked = true;          


            // display the small plus
            if (hiddenSubNodes)
            {
                Button btn = new Button();
                btn.Name = "plus" + ID;
                btn.FontSize = fontSize / 2;
                btn.Click += new RoutedEventHandler(btn_Click);
                btn.Height = plusButtonHeight;
                btn.Width = plusButtonWidth;
                btn.Content = "+";
                btn.SetValue(Canvas.LeftProperty, x - btn.Width / 2);
                btn.SetValue(Canvas.TopProperty, y + buttonHeight + minVerticalSpace - minVerticalSpace / 2);
               // canvas.Children.Add(btn);
                nb.ButtonBase.IsChecked = false;
            }
            if(subNodes && !hiddenSubNodes)
            //if (subNodes)
                DrawLine(canvas, x - 3, y + buttonHeight, x - 3, y + buttonHeight + minVerticalSpace);


            if (!subNodes && !hiddenSubNodes)
            {
                nb.ButtonBase.Visibility = Visibility.Hidden;
            }
        }


  
        #endregion


        #region Events
        void btn_Click(object sender, RoutedEventArgs e)
        {
           ToggleButton clicked = (ToggleButton)sender;
           
            btnClicked(clicked.Tag.ToString().Replace("plus", ""));


            Debug.WriteLine(clicked.IsChecked);
        }


        public void btnClicked(string clickedButtonName)
        {
            for (int i = 0; i < persons.Count; i++)
            {
                if (persons[i].ID == clickedButtonName)
                {
                    MyCanvas.Children.Clear();
                    var results = from n in persons
                                  where n.ManagerID == persons[i].ID
                                  select n;


                    persons[i].Collapsed = !persons[i].Collapsed;
                    foreach (Person p in results)
                    {
                        p.Opened = !persons[i].Collapsed;
                    }


                    Refresh();
                    return;
                }
            }
        }
        #endregion
        private void printPos(UIElement el)
        {


            int x = (int)Canvas.GetLeft(el);


            int y = (int)Canvas.GetTop(el);


            // textPos.Text = string.Format("x:{0} y:{1}", x, y);


        }






        private bool _isDrag = false;


        private Point _dragOffset;


        private void ele_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {


            UIElement el = sender as UIElement;


            if (el != null)
            {


                _isDrag = true;


                _dragOffset = e.GetPosition(el);


                el.CaptureMouse();


            }


        }






        private void ele_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {


            if (_isDrag == true)
            {


                UIElement el = sender as UIElement;


                el.ReleaseMouseCapture();


                _isDrag = false;


            }


        }






        private void ele_MouseMove(object sender, MouseEventArgs e)
        {


            if (_isDrag == true)
            {


                Point pt = Mouse.GetPosition(board);


                UIElement el = sender as UIElement;


                Canvas.SetLeft(el, pt.X - _dragOffset.X);


                Canvas.SetTop(el, pt.Y - _dragOffset.Y);


                printPos(el);


            }


        }
    }
}


UserCortrol:

NodeBox.xaml

<UserControl x:Class="Topographies.NodeBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="140" Height="80">
    <UserControl.Resources>
        <Style TargetType="ToggleButton">
            <Setter Property="Background" Value="Gray"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ToggleButton">
                        <Border BorderBrush="Gray" BorderThickness="1" Background="{TemplateBinding Background}">
                            <Grid>
                                <Path Data="M 1,4 8,4" Stroke="Black" StrokeThickness="1" ></Path>
                                <Path Data="M 4,1 4,9" Margin="0.5,0,0,1" Stroke="Black" Name="Path" StrokeThickness="1"></Path>
                                <ContentPresenter>
                                </ContentPresenter>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="Path" Property="Visibility" Value="Hidden"></Setter>
                                <Setter Property="Background" Value="Transparent"></Setter>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="False">
                                <Setter TargetName="Path" Property="Visibility" Value="Visible"></Setter>
                                <Setter Property="Background" Value="Gray"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>


        <Grid>
        <Canvas x:Name="canvMain" MouseEnter="canvMain_MouseEnter" MouseLeave="canvMain_MouseLeave" >
            <Rectangle x:Name="recBorder" RadiusX="5" RadiusY="5" Stroke="CornflowerBlue" StrokeThickness="2">
                <Rectangle.Fill>
                    <SolidColorBrush Color='#f2f3fd' />
                </Rectangle.Fill>
            </Rectangle>
            <TextBlock TextAlignment="left" x:Name="tbEmployeeName" Width="130" Height="20" Foreground="Black" Canvas.Left="5" FontWeight="Bold"></TextBlock>
            <TextBlock TextAlignment="left" x:Name="tbTitle" Width="130" Height="20" Foreground="Black" Canvas.Left="5"></TextBlock>
            <TextBlock TextAlignment="left" x:Name="tbDepartment" Width="130" Height="20" Foreground="Black" Canvas.Left="5"></TextBlock>
            <TextBlock TextAlignment="left" x:Name="tbExtension" Width="130" Height="20" Foreground="Black" Canvas.Left="5" FontFamily="Portable User Interface"></TextBlock>


            <Canvas.Resources>
                <!--<Storyboard x:Name="mouseEnter">
                <ColorAnimation 
                Duration='00:00:01' 
                To='#ffffcc' 
                Storyboard.TargetName='recBorder'    
                Storyboard.TargetProperty='(Shape.Fill).(SolidColorBrush.Color)' />
            </Storyboard>
            <Storyboard x:Name='mouseLeave'>
                <ColorAnimation 
                Duration='00:00:00' 
                To='#f2f3fd' 
                Storyboard.TargetName='recBorder'
                Storyboard.TargetProperty='(Shape.Fill).(SolidColorBrush.Color)' />
            </Storyboard>-->


            </Canvas.Resources>


        </Canvas>
        <ToggleButton Name="ButtonBase"  Height="10" Width="10" Margin="-5,-5,0,-5"  HorizontalAlignment="Center" VerticalAlignment="Bottom"></ToggleButton>
    </Grid>
 
  
</UserControl>

NodeBox.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;


namespace Topographies
{
    /// <summary>
    /// NodeBox.xaml 的交互逻辑
    /// </summary>
    public partial class NodeBox : UserControl
    {
        private double _fontSize = 10;


        public NodeBox(double scale)
        {
            _Scale = scale;
            InitializeComponent();


            tbEmployeeName.FontSize = _fontSize * Scale;
            tbEmployeeName.SetValue(Canvas.TopProperty, 5 * scale);
            tbEmployeeName.SetValue(Canvas.LeftProperty, 5 * scale);
            tbEmployeeName.Height = 20 * scale;
            tbEmployeeName.Width = 130 * scale;
            tbEmployeeName.TextWrapping = TextWrapping.NoWrap;
            tbEmployeeName.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 130 * scale, 20 * scale) };


            tbTitle.FontSize = _fontSize * Scale;
            tbTitle.SetValue(Canvas.TopProperty, 20 * scale);
            tbTitle.SetValue(Canvas.LeftProperty, 5 * scale);
            tbTitle.Height = 20 * scale;
            tbTitle.Width = 130 * scale;
            tbTitle.TextWrapping = TextWrapping.NoWrap;
            tbTitle.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 130 * scale, 20 * scale) };


            tbDepartment.FontSize = _fontSize * Scale;
            tbDepartment.SetValue(Canvas.TopProperty, 35 * scale);
            tbDepartment.SetValue(Canvas.LeftProperty, 5 * scale);
            tbDepartment.Height = 20 * scale;
            tbDepartment.TextWrapping = TextWrapping.NoWrap;
            tbDepartment.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 130 * scale, 20 * scale) };


            tbExtension.FontSize = _fontSize * Scale;
            tbExtension.SetValue(Canvas.TopProperty, 60 * scale);
            tbExtension.SetValue(Canvas.LeftProperty, 5 * scale);
            tbExtension.Height = 20 * scale;
            tbExtension.TextWrapping = TextWrapping.NoWrap;
            tbExtension.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 130 * scale, 20 * scale) };


            recBorder.StrokeThickness = 2 * scale;
            recBorder.RadiusX = 5 * scale;
            recBorder.RadiusY = 5 * scale;
            recBorder.Width = this.Width * scale;
            recBorder.Height = this.Height * scale;
        }


        private double _Scale = 1;
        public double Scale
        {
            get
            {
                return _Scale;
            }
            set
            {
                _Scale = value;
            }
        }


        private string _ID;
        public string ID
        {
            get
            {
                return _ID;
            }
            set
            {
                _ID = value;
            }
        }


        private string _EmployeeName;
        public string EmployeeName
        {
            get
            {
                return _EmployeeName;
            }
            set
            {
                _EmployeeName = value;
                tbEmployeeName.Text = _EmployeeName;
            }
        }


        private string _Title;
        public string Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
                tbTitle.Text = _Title;
            }
        }


        private string _Target;
        public string Target
        {
            get
            {
                return _Target;
            }
            set
            {
                _Target = value;
                ButtonBase.Tag = _Target;
            }
        }


        private string _Department;
        public string Department
        {
            get
            {
                return _Department;
            }
            set
            {
                _Department = value;
                tbDepartment.Text = _Department;
            }
        }


        private string _Extension;
        public string Extension
        {
            get
            {
                return _Extension;
            }
            set
            {
                _Extension = value;


                if (!string.IsNullOrEmpty(_Extension))
                {
                    tbExtension.Text = "ext. :" + _Extension;
                }


            }
        }


        private void canvMain_MouseEnter(object sender, MouseEventArgs e)
        {
            //this.mouseEnter.Begin();
        }


        private void canvMain_MouseLeave(object sender, MouseEventArgs e)
        {
           // this.mouseLeave.Begin();
        }


        
    }
}


Person.cs

using System;


namespace Topographies
{
    public class Person
    {
        public string ID;
        public string Name;
        public string ManagerID;
        public string Title;
        public string Department;
        public string Extension;
        public string Email;


        #region More Fileds
        public int Level = 1;
        public int SubNodes = 0;
        public int HiddenSubNodes = 0;
        public int NodeOrder = 1;
        public double MinChildWidth;
        public double X;
        public double StartX;
        public Boolean Opened = false;
        public Boolean Collapsed = true;
        #endregion


        public static Person GetPerson(string id, string name, string managerID, string title, string department, string extension, string email)
        {
            Person p = new Person();
            p.ID = id;
            p.Name = name;
            p.ManagerID = managerID;
            p.Title = title;
            p.Department = department;
            p.Extension = extension;
            p.Email = email;
            return p;
        }

    }
}


Utilcs.cs

using System;
using System.Windows.Media;


namespace Topographies


{
    public static class Util
    {
        /// <summary>
        /// Generate a color based on HEX values
        /// </summary>
        /// <param name="myColor"></param>
        /// <returns></returns>
        public static SolidColorBrush GetColorFromHex(string myColor)
        {
            return new SolidColorBrush(
                Color.FromArgb(
                    Convert.ToByte(myColor.Substring(1, 2), 16),
                    Convert.ToByte(myColor.Substring(3, 2), 16),
                    Convert.ToByte(myColor.Substring(5, 2), 16),
                    Convert.ToByte(myColor.Substring(7, 2), 16)
                )
            );
        }
    }
}

OrgChart_Data.xml

<?xml version="1.0" encoding="utf-8" ?>
<Persons>
  <Person>
    <ID>1</ID>
    <Name>Name 1</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1630</Extension>
    <Email>email@domain.com</Email>
    <ManagerID></ManagerID>
  </Person>
  <Person>
    <ID>2</ID>
    <Name>Name 2</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1379</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>1</ManagerID>
  </Person>
  <Person>
    <ID>3</ID>
    <Name>Name 3</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1681</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>1</ManagerID>
  </Person>
  <Person>
    <ID>4</ID>
    <Name>Name 4</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1634</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>1</ManagerID>
  </Person>
  <Person>
    <ID>5</ID>
    <Name>Name 5</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1460</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>4</ManagerID>
  </Person>
  <Person>
    <ID>6</ID>
    <Name>Name 6</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1331</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>4</ManagerID>
  </Person>
  <Person>
    <ID>7</ID>
    <Name>Name 7</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1270</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>4</ManagerID>
  </Person>
  <Person>
    <ID>8</ID>
    <Name>Name 8</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1670</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>4</ManagerID>
  </Person>
  <Person>
    <ID>9</ID>
    <Name>Name 9</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1613</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>1</ManagerID>
  </Person>
  <Person>
    <ID>10</ID>
    <Name>Name 10</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1376</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>9</ManagerID>
  </Person>
  <Person>
    <ID>11</ID>
    <Name>Name 11</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1860</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>9</ManagerID>
  </Person>
  <Person>
    <ID>12</ID>
    <Name>Name 12</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>2548</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>11</ManagerID>
  </Person>
  <Person>
    <ID>13</ID>
    <Name>Name 13</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1566</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>12</ManagerID>
  </Person>
  <Person>
    <ID>14</ID>
    <Name>Name 14</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1348</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>1</ManagerID>
  </Person>
  <Person>
    <ID>15</ID>
    <Name>Name 15</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>2545</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>14</ManagerID>
  </Person>
  <Person>
    <ID>16</ID>
    <Name>Name 16</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1871</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>15</ManagerID>
  </Person>
  <Person>
    <ID>17</ID>
    <Name>Name 17</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1817</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>16</ManagerID>
  </Person>
  <Person>
    <ID>18</ID>
    <Name>Name 18</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1529</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>16</ManagerID>
  </Person>
  <Person>
    <ID>19</ID>
    <Name>Name 19</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>2567</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>16</ManagerID>
  </Person>
  <Person>
    <ID>20</ID>
    <Name>Name 20</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1557</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>16</ManagerID>
  </Person>
  <Person>
    <ID>21</ID>
    <Name>Name 21</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1529</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>18</ManagerID>
  </Person>
  <Person>
    <ID>22</ID>
    <Name>Name 22</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1529</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>18</ManagerID>
  </Person>
  <Person>
    <ID>23</ID>
    <Name>Name 23</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1681</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>3</ManagerID>
  </Person>
  <Person>
    <ID>24</ID>
    <Name>Name 24</Name>
    <Title>Title</Title>
    <Department>Department</Department>
    <Extension>1681</Extension>
    <Email>email@domain.com</Email>
    <ManagerID>3</ManagerID>
  </Person>
</Persons>

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值