WPF 拓扑图 Topographies

MainWindow.xaml

        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">
   
       
       
            MouseLeftButtonUp="ele_MouseLeftButtonUp" MouseMove="ele_MouseMove">
       

   
     

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
{
    ///


    /// MainWindow.xaml 的交互逻辑
    ///

    public partial class MainWindow : Window
    {
        public List persons = new List();
        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

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="140" Height="80">
   
       
   



       
       
           
               
                   
               

           

           
           
           
           


           
               


           



       

       
   

 
  

NodeBox.xaml.cs

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


namespace Topographies
{
    ///


    /// NodeBox.xaml 的交互逻辑
    ///

    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
    {
        ///


        /// Generate a color based on HEX values
        ///

        ///
        ///
        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



 
    1
    Name 1
    Title
    Department
    1630
    [email protected]
   
 

 
    2
    Name 2
    Title
    Department
    1379
    [email protected]
    1
 

 
    3
    Name 3
    Title
    Department
    1681
    [email protected]
    1
 

 
    4
    Name 4
    Title
    Department
    1634
    [email protected]
    1
 

 
    5
    Name 5
    Title
    Department
    1460
    [email protected]
    4
 

 
    6
    Name 6
    Title
    Department
    1331
    [email protected]
    4
 

 
    7
    Name 7
    Title
    Department
    1270
    [email protected]
    4
 

 
    8
    Name 8
    Title
    Department
    1670
    [email protected]
    4
 

 
    9
    Name 9
    Title
    Department
    1613
    [email protected]
    1
 

 
    10
    Name 10
    Title
    Department
    1376
    [email protected]
    9
 

 
    11
    Name 11
    Title
    Department
    1860
    [email protected]
    9
 

 
    12
    Name 12
    Title
    Department
    2548
    [email protected]
    11
 

 
    13
    Name 13
    Title
    Department
    1566
    [email protected]
    12
 

 
    14
    Name 14
    Title
    Department
    1348
    [email protected]
    1
 

 
    15
    Name 15
    Title
    Department
    2545
    [email protected]
    14
 

 
    16
    Name 16
    Title
    Department
    1871
    [email protected]
    15
 

 
    17
    Name 17
    Title
    Department
    1817
    [email protected]
    16
 

 
    18
    Name 18
    Title
    Department
    1529
    [email protected]
    16
 

 
    19
    Name 19
    Title
    Department
    2567
    [email protected]
    16
 

 
    20
    Name 20
    Title
    Department
    1557
    [email protected]
    16
 

 
    21
    Name 21
    Title
    Department
    1529
    [email protected]
    18
 

 
    22
    Name 22
    Title
    Department
    1529
    [email protected]
    18
 

 
    23
    Name 23
    Title
    Department
    1681
    [email protected]
    3
 

 
    24
    Name 24
    Title
    Department
    1681
    [email protected]
    3
 


你可能感兴趣的:(WPF)