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>