Przeglądaj źródła

Reingold-Tilford 一个例子 http://www.codeproject.com/KB/WPF/LayeredTreeDraw.aspx

tanghai 14 lat temu
rodzic
commit
f573aa8966

+ 13 - 0
CSharp/CSharp.sln

@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeCanvas", "Modules\TreeC
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{EEC1B63E-05B1-4107-9627-B2542EED2B28}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BehaviorTree", "Controls\BehaviorTree\BehaviorTree.csproj", "{88A0D086-1C51-466C-9123-793FFB5714B8}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -51,11 +53,22 @@ Global
 		{6CD185D1-08E0-4729-A999-2D5B57BA8193}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{6CD185D1-08E0-4729-A999-2D5B57BA8193}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{6CD185D1-08E0-4729-A999-2D5B57BA8193}.Release|x86.ActiveCfg = Release|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{88A0D086-1C51-466C-9123-793FFB5714B8}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{6CD185D1-08E0-4729-A999-2D5B57BA8193} = {C4C64188-4FAE-4CC3-A9E6-D9D4AF7429B6}
+		{88A0D086-1C51-466C-9123-793FFB5714B8} = {EEC1B63E-05B1-4107-9627-B2542EED2B28}
 	EndGlobalSection
 EndGlobal

+ 261 - 0
CSharp/Controls/BehaviorTree/BehaviorPanel.cs

@@ -0,0 +1,261 @@
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Shapes;
+
+namespace BehaviorTree
+{
+	public class BehaviorPanel : Panel
+	{
+		private LayeredTreeDraw ltd;
+		private int iNextNameSuffix = 0;
+		private Path pthConnections = null;
+
+		public static readonly DependencyProperty VerticalBufferProperty =
+			DependencyProperty.Register(
+				"VerticalBuffer",
+				typeof(double),
+				typeof(BehaviorPanel),
+				null
+			);
+
+		public static readonly DependencyProperty VerticalJustificationProperty =
+			DependencyProperty.Register(
+				"VerticalJustification",
+				typeof(VerticalJustification),
+				typeof(BehaviorPanel),
+				null
+			);
+
+		public readonly static DependencyProperty HorizontalBufferSubtreeProperty =
+			DependencyProperty.Register(
+				"HorizontalBufferSubtree",
+				typeof(double),
+				typeof(BehaviorPanel),
+				null
+			);
+
+		public readonly static DependencyProperty HorizontalBufferProperty =
+			DependencyProperty.Register(
+				"HorizontalBuffer",
+				typeof(double),
+				typeof(BehaviorPanel),
+				null
+			);
+
+		public static readonly DependencyProperty RootProperty =
+			DependencyProperty.Register(
+				"Root",
+				typeof(String),
+				typeof(BehaviorPanel),
+				null
+			);
+
+		private static Point PtFromPoint(Point dpt)
+		{
+			return new Point(dpt.X, dpt.Y);
+		}
+
+		public string Root
+		{
+			get
+			{
+				return (string)GetValue(RootProperty);
+			}
+			set
+			{
+				SetValue(RootProperty, value);
+			}
+		}
+
+		public VerticalJustification VerticalJustification
+		{
+			get
+			{
+				return (VerticalJustification)GetValue(VerticalJustificationProperty);
+			}
+			set
+			{
+				SetValue(VerticalJustificationProperty, value);
+			}
+		}
+
+		public double VerticalBuffer
+		{
+			get { return (double)GetValue(VerticalBufferProperty); }
+			set { SetValue(VerticalBufferProperty, value); }
+		}
+
+		public double HorizontalBufferSubtree
+		{
+			get { return (double)GetValue(HorizontalBufferSubtreeProperty); }
+			set { SetValue(HorizontalBufferSubtreeProperty, value); }
+		}
+
+		public double HorizontalBuffer
+		{
+			get { return (double)GetValue(HorizontalBufferProperty); }
+			set { SetValue(HorizontalBufferProperty, value); }
+		}
+
+		private void SetParents(TreeNode tnRoot)
+		{
+			// First pass to clear all parents
+			foreach (UIElement uiel in Children)
+			{
+				TreeNode tn = uiel as TreeNode;
+				if (tn != null)
+				{
+					tn.ClearParent();
+				}
+			}
+
+			// Second pass to properly set them from their children...
+			foreach (UIElement uiel in Children)
+			{
+				TreeNode tn = uiel as TreeNode;
+				if (tn != null && tn != tnRoot)
+				{
+					tn.SetParent();
+				}
+			}
+		}
+
+		public void Clear()
+		{
+			Children.Clear();
+			pthConnections = null;
+		}
+
+		private void SetName(TreeNode tn, string strName)
+		{
+			tn.Name = strName;
+			tn.SetValue(Panel.NameProperty, strName);
+		}
+
+		public TreeNode AddRoot(Object objContent, string strName)
+		{
+			TreeNode tnNew = new TreeNode();
+			SetName(tnNew, strName);
+			tnNew.Content = objContent;
+			Children.Add(tnNew);
+			Root = strName;
+			return tnNew;
+		}
+
+		public TreeNode AddRoot(Object objContent)
+		{
+			return AddRoot(objContent, StrNextName());
+		}
+
+		public TreeNode AddNode(Object objContent, string strName, string strParent)
+		{
+			TreeNode tnNew = new TreeNode();
+			SetName(tnNew, strName);
+			tnNew.Content = objContent;
+			tnNew.TreeParent = strParent;
+			Children.Add(tnNew);
+			return tnNew;
+		}
+
+		private string StrNextName()
+		{
+			return "__TreeNode" + iNextNameSuffix++;
+		}
+
+		public TreeNode AddNode(Object objContent, string strName, TreeNode tnParent)
+		{
+			return AddNode(objContent, strName, tnParent.Name);
+		}
+
+		public TreeNode AddNode(Object objContent, TreeNode tnParent)
+		{
+			return AddNode(objContent, StrNextName(), tnParent.Name);
+		}
+
+		protected override Size MeasureOverride(Size availableSize)
+		{
+			if (Children.Count == 0)
+			{
+				return new Size(100, 20);
+			}
+
+			if (pthConnections != null && Children.Contains(pthConnections))
+			{
+				Children.Remove(pthConnections);
+				pthConnections = null;
+			}
+
+			Size szFinal = new Size(0, 0);
+			string strRoot = Root;
+			TreeNode tnRoot = this.FindName(strRoot) as TreeNode;
+
+			foreach (UIElement uiel in Children)
+			{
+				uiel.Measure(availableSize);
+				Size szThis = uiel.DesiredSize;
+
+				if (szThis.Width > szFinal.Width || szThis.Height > szFinal.Height)
+				{
+					szFinal = new Size(
+						Math.Max(szThis.Width, szFinal.Width),
+						Math.Max(szThis.Height, szFinal.Height));
+				}
+			}
+
+			if (tnRoot != null)
+			{
+				SetParents(tnRoot);
+				ltd = new LayeredTreeDraw(tnRoot, HorizontalBuffer, HorizontalBufferSubtree, VerticalBuffer, VerticalJustification.TOP);
+				ltd.LayoutTree();
+				szFinal = new Size(ltd.PxOverallWidth, ltd.PxOverallHeight);
+			}
+
+			// Put in the connections too...
+			if (ltd.Connections != null)
+			{
+				pthConnections = new Path();
+				PathGeometry pg = new PathGeometry();
+				pthConnections.Stroke = new SolidColorBrush(Colors.Black);
+				pthConnections.StrokeThickness = 1.0;
+				pg.Figures = new PathFigureCollection();
+
+				foreach (TreeConnection tcn in ltd.Connections)
+				{
+					PathFigure pf = new PathFigure();
+
+					pf.StartPoint = PtFromPoint(tcn.LstPt[0]);
+					pf.IsClosed = false;
+					pf.Segments = new PathSegmentCollection();
+					for (int iPt = 1; iPt < tcn.LstPt.Count; iPt++)
+					{
+						LineSegment ls = new LineSegment();
+						ls.Point = PtFromPoint(tcn.LstPt[iPt]);
+						pf.Segments.Add(ls);
+					}
+					pg.Figures.Add(pf);
+				}
+				pthConnections.Data = pg;
+				Children.Add(pthConnections);
+				pthConnections.Measure(availableSize);
+			}
+			return szFinal;
+		}
+
+		protected override Size ArrangeOverride(Size finalSize)
+		{
+			foreach (UIElement uiel in Children)
+			{
+				TreeNode tn = uiel as TreeNode;
+				Point ptLocation = new Point(0, 0);
+				if (tn != null)
+				{
+					ptLocation = new Point(ltd.X(tn), ltd.Y(tn));
+				}
+				uiel.Arrange(new Rect(ptLocation, uiel.DesiredSize));
+			}
+			return finalSize;
+		}
+	}
+}

+ 75 - 0
CSharp/Controls/BehaviorTree/BehaviorTree.csproj

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{88A0D086-1C51-466C-9123-793FFB5714B8}</ProjectGuid>
+    <OutputType>library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>BehaviorTree</RootNamespace>
+    <AssemblyName>BehaviorTree</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ITreeNode.cs" />
+    <Compile Include="LayeredTreeDraw.cs" />
+    <Compile Include="TreeConnection.cs" />
+    <Compile Include="TreeNode.cs" />
+    <Compile Include="TreeNodeGroup.cs" />
+    <Compile Include="BehaviorPanel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <AppDesigner Include="Properties\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 19 - 0
CSharp/Controls/BehaviorTree/ITreeNode.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BehaviorTree
+{
+	public interface ITreeNode
+	{
+		// PrivateNodeInfo is a cookie used by GraphLayout to keep track of information on
+		// a per node basis.  The ITreeNode implementer just has to provide a way to
+		// save and retrieve this cookie.
+		Object PrivateNodeInfo { get; set; }
+		TreeNodeGroup TreeChildren { get; }
+		double TreeWidth { get; }
+		double TreeHeight { get; }
+		bool Collapsed { get; }
+	}
+}

+ 492 - 0
CSharp/Controls/BehaviorTree/LayeredTreeDraw.cs

@@ -0,0 +1,492 @@
+#define FIX
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+
+namespace BehaviorTree
+{
+	public enum VerticalJustification
+	{
+		TOP,
+		CENTER,
+		BOTTOM
+	}
+
+	public class LayeredTreeDraw
+	{
+		ITreeNode tnRoot;
+		double pxBufferHorizontal;
+		double pxBufferHorizontalSubtree;
+		double pxBufferVertical;
+		List<TreeConnection> lsttcn = new List<TreeConnection>();
+		List<double> lstLayerHeight = new List<double>();
+		VerticalJustification vj;
+		static TreeNodeGroup tngEmpty = new TreeNodeGroup();
+
+		public double PxOverallHeight 
+		{ 
+			get; 
+			private set; 
+		}
+
+		public double PxOverallWidth
+		{
+			get
+			{
+				return Info(tnRoot).SubTreeWidth;
+			}
+		}
+
+		public List<TreeConnection> Connections
+		{
+			get
+			{
+				return lsttcn;
+			}
+		}
+
+		public LayeredTreeDraw(
+			ITreeNode tnRoot, double pxBufferHorizontal,
+			double pxBufferHorizontalSubtree, double pxBufferVertical,
+			VerticalJustification vj)
+		{
+			this.pxBufferHorizontal = pxBufferHorizontal;
+			this.pxBufferHorizontalSubtree = pxBufferHorizontalSubtree;
+			this.pxBufferVertical = pxBufferVertical;
+			PxOverallHeight = 0.0;
+			this.tnRoot = tnRoot;
+			this.vj = vj;
+		}
+
+		private static LayeredTreeInfo Info(ITreeNode ign)
+		{
+			return (LayeredTreeInfo)ign.PrivateNodeInfo;
+		}
+
+		public double X(ITreeNode tn)
+		{
+			if (Info(tn) == null)
+			{
+				return 0;
+			}
+			return Info(tn).pxFromLeft;
+		}
+
+		public double Y(ITreeNode tn)
+		{
+			if (Info(tn) == null)
+			{
+				return 0;
+			}
+			return Info(tn).pxFromTop;
+		}
+
+		static public IEnumerable<T> VisibleDescendants<T>(ITreeNode tn)
+		{
+			foreach (ITreeNode tnCur in tn.TreeChildren)
+			{
+				if (!tnCur.Collapsed)
+				{
+					foreach (T item in VisibleDescendants<T>(tnCur))
+					{
+						yield return item;
+					}
+				}
+				yield return (T)tnCur;
+			}
+		}
+
+
+		static public IEnumerable<T> Descendants<T>(ITreeNode tn)
+		{
+			foreach (ITreeNode tnCur in tn.TreeChildren)
+			{
+				foreach (T item in Descendants<T>(tnCur))
+				{
+					yield return item;
+				}
+				yield return (T)tnCur;
+			}
+		}
+
+		public void LayoutTree()
+		{
+			LayoutTree(tnRoot, 0);
+			DetermineFinalPositions(tnRoot, 0, 0, Info(tnRoot).pxLeftPosRelativeToBoundingBox);
+		}
+
+		private void LayoutTree(ITreeNode tnRoot, int iLayer)
+		{
+			if (GetChildren(tnRoot).Count == 0)
+			{
+				LayoutLeafNode(tnRoot);
+			}
+			else
+			{
+				LayoutInteriorNode(tnRoot, iLayer);
+			}
+			UpdateLayerHeight(tnRoot, iLayer);
+		}
+
+		private static void LayoutLeafNode(ITreeNode tnRoot)
+		{
+			double width = tnRoot.TreeWidth;
+			LayeredTreeInfo lti = new LayeredTreeInfo(width, tnRoot);
+			lti.lstPosLeftBoundaryRelativeToRoot.Add(0);
+			lti.lstPosRightBoundaryRelativeToRoot.Add(width);
+			tnRoot.PrivateNodeInfo = lti;
+		}
+
+		private void LayoutInteriorNode(ITreeNode tnRoot, int iLayer)
+		{
+			ITreeNode tnLast = null;
+			TreeNodeGroup tng = GetChildren(tnRoot);
+			ITreeNode itn = tng[0];
+			LayeredTreeInfo ltiThis;
+
+			LayoutAllOurChildren(iLayer, tnLast, tng);
+
+			// This width doesn't account for the parent node's width...
+			ltiThis = new LayeredTreeInfo(CalculateWidthFromInterChildDistances(tnRoot), tnRoot);
+			tnRoot.PrivateNodeInfo = ltiThis;
+
+			// ...so that this centering may place the parent node negatively while the "width" is the width of
+			// all the child nodes.
+			CenterOverChildren(tnRoot, ltiThis);
+			DetermineParentRelativePositionsOfChildren(tnRoot);
+			CalculateBoundaryLists(tnRoot);
+		}
+
+		private void LayoutAllOurChildren(int iLayer, ITreeNode tnLast, TreeNodeGroup tng)
+		{
+			List<Double> lstLeftToBB = new List<double>();
+			List<int> lstResponsible = new List<int>();
+			for (int i = 0; i < tng.Count; i++)
+			{
+				ITreeNode tn = tng[i];
+				LayoutTree(tn, iLayer + 1);
+				RepositionSubtree(i, tng, lstLeftToBB, lstResponsible);
+				tnLast = tn;
+			}
+		}
+
+		private static void CenterOverChildren(ITreeNode tnRoot, LayeredTreeInfo ltiThis)
+		{
+			// We should be centered between  the connection points of our children...
+			ITreeNode tnLeftMost = tnRoot.TreeChildren.LeftMost();
+			double pxLeftChild = Info(tnLeftMost).pxLeftPosRelativeToBoundingBox + tnLeftMost.TreeWidth / 2;
+			ITreeNode tnRightMost = tnRoot.TreeChildren.RightMost();
+			double pxRightChild = Info(tnRightMost).pxLeftPosRelativeToBoundingBox + tnRightMost.TreeWidth / 2;
+			ltiThis.pxLeftPosRelativeToBoundingBox = (pxLeftChild + pxRightChild - tnRoot.TreeWidth) / 2;
+
+			// If the root node was wider than the subtree, then we'll have a negative position for it.  We need
+			// to readjust things so that the left of the root node represents the left of the bounding box and
+			// the child distances to the Bounding box need to be adjusted accordingly.
+			if (ltiThis.pxLeftPosRelativeToBoundingBox < 0)
+			{
+				foreach (ITreeNode tnChildCur in tnRoot.TreeChildren)
+				{
+					Info(tnChildCur).pxLeftPosRelativeToBoundingBox -= ltiThis.pxLeftPosRelativeToBoundingBox;
+				}
+				ltiThis.pxLeftPosRelativeToBoundingBox = 0;
+			}
+		}
+
+		private void DetermineParentRelativePositionsOfChildren(ITreeNode tnRoot)
+		{
+			LayeredTreeInfo ltiRoot = Info(tnRoot);
+			foreach (ITreeNode tn in GetChildren(tnRoot))
+			{
+				LayeredTreeInfo ltiCur = Info(tn);
+				ltiCur.pxLeftPosRelativeToParent = ltiCur.pxLeftPosRelativeToBoundingBox - ltiRoot.pxLeftPosRelativeToBoundingBox;
+			}
+		}
+
+		private double CalculateWidthFromInterChildDistances(ITreeNode tnRoot)
+		{
+			double pxWidthCur;
+			LayeredTreeInfo lti;
+			double pxWidth = 0.0;
+
+			lti = Info(tnRoot.TreeChildren.LeftMost());
+			pxWidthCur = lti.pxLeftPosRelativeToBoundingBox;
+
+			// If a subtree extends deeper than it's left neighbors then at that lower level it could potentially extend beyond those neighbors
+			// on the left.  We have to check for this and make adjustements after the loop if it occurred.
+			double pxUndercut = 0.0;
+
+			foreach (ITreeNode tn in tnRoot.TreeChildren)
+			{
+				lti = Info(tn);
+				pxWidthCur += lti.pxToLeftSibling;
+
+				if (lti.pxLeftPosRelativeToBoundingBox > pxWidthCur)
+				{
+					pxUndercut = Math.Max(pxUndercut, lti.pxLeftPosRelativeToBoundingBox - pxWidthCur);
+				}
+
+				// pxWidth might already be wider than the current node's subtree if earlier nodes "undercut" on the
+				// right hand side so we have to take the Max here...
+				pxWidth = Math.Max(pxWidth, pxWidthCur + lti.SubTreeWidth - lti.pxLeftPosRelativeToBoundingBox);
+
+				// After this next statement, the BoundingBox we're relative to is the one of our parent's subtree rather than
+				// our own subtree (with the exception of undercut considerations)
+				lti.pxLeftPosRelativeToBoundingBox = pxWidthCur;
+			}
+			if (pxUndercut > 0.0)
+			{
+				foreach (ITreeNode tn in tnRoot.TreeChildren)
+				{
+					Info(tn).pxLeftPosRelativeToBoundingBox += pxUndercut;
+				}
+				pxWidth += pxUndercut;
+			}
+
+			// We are never narrower than our root node's width which we haven't taken into account yet so
+			// we do that here.
+			return Math.Max(tnRoot.TreeWidth, pxWidth);
+		}
+
+		private void CalculateBoundaryLists(ITreeNode tnRoot)
+		{
+			LayeredTreeInfo lti = Info(tnRoot);
+			lti.lstPosLeftBoundaryRelativeToRoot.Add(0.0);
+			lti.lstPosRightBoundaryRelativeToRoot.Add(tnRoot.TreeWidth);
+			DetermineBoundary(tnRoot.TreeChildren, true /* fLeft */, lti.lstPosLeftBoundaryRelativeToRoot);
+			DetermineBoundary(tnRoot.TreeChildren.Reverse(), false /* fLeft */, lti.lstPosRightBoundaryRelativeToRoot);
+
+		}
+
+		private void DetermineBoundary(IEnumerable<ITreeNode> entn, bool fLeft, List<double> lstPos)
+		{
+			int cLayersDeep = 1;
+			List<double> lstPosCur;
+			foreach (ITreeNode tnChild in entn)
+			{
+				LayeredTreeInfo ltiChild = Info(tnChild);
+
+				if (fLeft)
+				{
+					lstPosCur = ltiChild.lstPosLeftBoundaryRelativeToRoot;
+				}
+				else
+				{
+					lstPosCur = ltiChild.lstPosRightBoundaryRelativeToRoot;
+				}
+
+				if (lstPosCur.Count >= lstPos.Count)
+				{
+					using (IEnumerator<double> enPosCur = lstPosCur.GetEnumerator())
+					{
+						for (int i = 0; i < cLayersDeep - 1; i++)
+						{
+							enPosCur.MoveNext();
+						}
+
+						while (enPosCur.MoveNext())
+						{
+							lstPos.Add(enPosCur.Current + ltiChild.pxLeftPosRelativeToParent);
+							cLayersDeep++;
+						}
+					}
+				}
+			}
+		}
+
+		private void ApportionSlop(int itn, int itnResponsible, TreeNodeGroup tngSiblings)
+		{
+			LayeredTreeInfo lti = Info(tngSiblings[itn]);
+			ITreeNode tnLeft = tngSiblings[itn - 1];
+
+			double pxSlop = lti.pxToLeftSibling - tnLeft.TreeWidth - pxBufferHorizontal;
+			if (pxSlop > 0)
+			{
+				for (int i = itnResponsible + 1; i < itn; i++)
+				{
+					Info(tngSiblings[i]).pxToLeftSibling += pxSlop * (i - itnResponsible) / (itn - itnResponsible);
+				}
+				lti.pxToLeftSibling -= (itn - itnResponsible - 1) * pxSlop / (itn - itnResponsible);
+			}
+		}
+
+		private void RepositionSubtree(
+				int itn, TreeNodeGroup tngSiblings,
+				List<double> lstLeftToBB, List<int> lsttnResponsible)
+		{
+			int itnResponsible;
+			ITreeNode tn = tngSiblings[itn];
+			LayeredTreeInfo lti = Info(tn);
+
+			if (itn == 0)
+			{
+				// No shifting but we still have to prepare the initial version of the
+				// left hand skeleton list
+				foreach (double pxRelativeToRoot in lti.lstPosRightBoundaryRelativeToRoot)
+				{
+					lstLeftToBB.Add(pxRelativeToRoot + lti.pxLeftPosRelativeToBoundingBox);
+					lsttnResponsible.Add(0);
+				}
+				return;
+			}
+
+			ITreeNode tnLeft = tngSiblings[itn - 1];
+			LayeredTreeInfo ltiLeft = Info(tnLeft);
+			int iLayer;
+			double pxHorizontalBuffer = pxBufferHorizontal;
+
+			double pxNewPosFromBB = PxCalculateNewPos(lti, lstLeftToBB, lsttnResponsible, out itnResponsible, out iLayer);
+			if (iLayer != 0)
+			{
+				pxHorizontalBuffer = pxBufferHorizontalSubtree;
+			}
+
+			lti.pxToLeftSibling = pxNewPosFromBB - lstLeftToBB.First() + tnLeft.TreeWidth + pxHorizontalBuffer;
+
+			int cLevels = Math.Min(lti.lstPosRightBoundaryRelativeToRoot.Count, lstLeftToBB.Count);
+			for (int i = 0; i < cLevels; i++)
+			{
+				lstLeftToBB[i] = lti.lstPosRightBoundaryRelativeToRoot[i] + pxNewPosFromBB + pxHorizontalBuffer;
+				lsttnResponsible[i] = itn;
+			}
+			for (int i = lstLeftToBB.Count; i < lti.lstPosRightBoundaryRelativeToRoot.Count; i++)
+			{
+				lstLeftToBB.Add(lti.lstPosRightBoundaryRelativeToRoot[i] + pxNewPosFromBB + pxHorizontalBuffer);
+				lsttnResponsible.Add(itn);
+			}
+
+			ApportionSlop(itn, itnResponsible, tngSiblings);
+		}
+
+		private double PxCalculateNewPos(
+				LayeredTreeInfo lti, List<double> lstLeftToBB,
+				List<int> lstitnResponsible, out int itnResponsible,
+				out int iLayerRet)
+		{
+			double pxOffsetToBB = lstLeftToBB[0];
+			int cLayers = Math.Min(lti.lstPosLeftBoundaryRelativeToRoot.Count, lstLeftToBB.Count);
+			double pxRootPosRightmost = 0.0;
+			iLayerRet = 0;
+
+			using (IEnumerator<double> enRight = lti.lstPosLeftBoundaryRelativeToRoot.GetEnumerator(),
+				enLeft = lstLeftToBB.GetEnumerator())
+			using (IEnumerator<int> enResponsible = lstitnResponsible.GetEnumerator())
+			{
+				itnResponsible = -1;
+
+				enRight.MoveNext();
+				enLeft.MoveNext();
+				enResponsible.MoveNext();
+				for (int iLayer = 0; iLayer < cLayers; iLayer++)
+				{
+					double pxLeftBorderFromBB = enLeft.Current;
+					double pxRightBorderFromRoot = enRight.Current;
+					double pxRightRootBasedOnThisLevel;
+					int itnResponsibleCur = enResponsible.Current;
+
+					enLeft.MoveNext();
+					enRight.MoveNext();
+					enResponsible.MoveNext();
+
+					pxRightRootBasedOnThisLevel = pxLeftBorderFromBB - pxRightBorderFromRoot;
+					if (pxRightRootBasedOnThisLevel > pxRootPosRightmost)
+					{
+						iLayerRet = iLayer;
+						pxRootPosRightmost = pxRightRootBasedOnThisLevel;
+						itnResponsible = itnResponsibleCur;
+					}
+				}
+			}
+			return pxRootPosRightmost;
+		}
+
+		private void UpdateLayerHeight(ITreeNode tnRoot, int iLayer)
+		{
+			while (lstLayerHeight.Count <= iLayer)
+			{
+				lstLayerHeight.Add(0.0);
+			}
+			lstLayerHeight[iLayer] = Math.Max(tnRoot.TreeHeight, lstLayerHeight[iLayer]);
+		}
+
+		private System.Double CalcJustify(double height, double pxRowHeight)
+		{
+			double dRet = 0.0;
+
+			switch (vj)
+			{
+				case VerticalJustification.TOP:
+					break;
+
+				case VerticalJustification.CENTER:
+					dRet = (pxRowHeight - height) / 2;
+					break;
+
+				case VerticalJustification.BOTTOM:
+					dRet = pxRowHeight - height;
+					break;
+			}
+			return dRet;
+		}
+
+		private TreeNodeGroup GetChildren(ITreeNode tn)
+		{
+			if (tn.Collapsed)
+			{
+				return tngEmpty;
+			}
+			return tn.TreeChildren;
+		}
+
+		private void DetermineFinalPositions(ITreeNode tn, int iLayer, double pxFromTop, double pxParentFromLeft)
+		{
+			double pxRowHeight = lstLayerHeight[iLayer];
+			LayeredTreeInfo lti = Info(tn);
+			double pxBottom;
+			Point dptOrigin;
+
+			lti.pxFromTop = pxFromTop + CalcJustify(tn.TreeHeight, pxRowHeight);
+			pxBottom = lti.pxFromTop + tn.TreeHeight;
+			if (pxBottom > PxOverallHeight)
+			{
+				PxOverallHeight = pxBottom;
+			}
+			lti.pxFromLeft = lti.pxLeftPosRelativeToParent + pxParentFromLeft;
+			dptOrigin = new Point(lti.pxFromLeft + tn.TreeWidth / 2, lti.pxFromTop + tn.TreeHeight);
+			iLayer++;
+			foreach (ITreeNode tnCur in GetChildren(tn))
+			{
+				List<Point> lstcpt = new List<Point>();
+				LayeredTreeInfo ltiCur = Info(tnCur);
+				lstcpt.Add(dptOrigin);
+				DetermineFinalPositions(tnCur, iLayer, pxFromTop + pxRowHeight + pxBufferVertical, lti.pxFromLeft);
+				lstcpt.Add(new Point(ltiCur.pxFromLeft + tnCur.TreeWidth / 2, ltiCur.pxFromTop));
+				lsttcn.Add(new TreeConnection(tn, tnCur, lstcpt));
+			}
+		}
+
+		private class LayeredTreeInfo
+		{
+			public double SubTreeWidth { get; set; }
+			public double pxLeftPosRelativeToParent { get; set; }
+			public double pxLeftPosRelativeToBoundingBox { get; set; }
+			public double pxToLeftSibling { get; set; }
+			public double pxFromTop { get; set; }
+			public double pxFromLeft { get; set; }
+			public ITreeNode ign { get; private set; }
+			public List<double> lstPosLeftBoundaryRelativeToRoot = new List<double>();
+			public List<double> lstPosRightBoundaryRelativeToRoot = new List<double>();
+
+			/// <summary>
+			/// Initializes a new instance of the GraphLayoutInfo class.
+			/// </summary>
+			public LayeredTreeInfo(double subTreeWidth, ITreeNode tn)
+			{
+				SubTreeWidth = subTreeWidth;
+				pxLeftPosRelativeToParent = 0;
+				pxFromTop = 0;
+				ign = tn;
+			}
+		}
+	}
+}

+ 23 - 0
CSharp/Controls/BehaviorTree/TreeConnection.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+
+namespace BehaviorTree
+{
+	public struct TreeConnection
+	{
+		public ITreeNode IgnParent { get; private set; }
+		public ITreeNode IgnChild { get; private set; }
+		public List<Point> LstPt { get; private set; }
+
+		public TreeConnection(ITreeNode ignParent, ITreeNode ignChild, List<Point> lstPt)
+			: this()
+		{
+			IgnChild = ignChild;
+			IgnParent = ignParent;
+			LstPt = lstPt;
+		}
+	}
+}

+ 159 - 0
CSharp/Controls/BehaviorTree/TreeNode.cs

@@ -0,0 +1,159 @@
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+
+namespace BehaviorTree
+{
+	public class TreeNode : ContentControl, ITreeNode
+	{
+		public static readonly DependencyProperty CollapsedProperty =
+			DependencyProperty.Register(
+				"Collapsed",
+				typeof(bool),
+				typeof(TreeNode),
+				new PropertyMetadata(
+					false,
+					CollapsePropertyChange
+				));
+
+		static public void CollapsePropertyChange(DependencyObject o, DependencyPropertyChangedEventArgs e)
+		{
+			TreeNode tn = o as TreeNode;
+			if (tn != null && tn.Collapsible)
+			{
+				bool fCollapsed = ((bool)e.NewValue);
+				foreach (TreeNode tnCur in LayeredTreeDraw.VisibleDescendants<TreeNode>(tn))
+				{
+					tnCur.Visibility = fCollapsed ? Visibility.Collapsed : Visibility.Visible;
+				}
+			}
+		}
+
+		public bool Collapsed
+		{
+			get { return (bool)GetValue(CollapsedProperty); }
+			set { SetValue(CollapsedProperty, value); }
+		}
+
+		public static readonly DependencyProperty CollapsibleProperty =
+			DependencyProperty.Register(
+				"Collapsible",
+				typeof(bool),
+				typeof(TreeNode),
+				new PropertyMetadata(
+					true,
+					CollapsiblePropertyChange
+				));
+
+		static public void CollapsiblePropertyChange(DependencyObject o, DependencyPropertyChangedEventArgs e)
+		{
+			TreeNode tn = o as TreeNode;
+			if (((bool)e.NewValue) == false && tn != null)
+			{
+				tn.Collapsed = false;
+			}
+		}
+
+		public bool Collapsible
+		{
+			get { return (bool)GetValue(CollapsibleProperty); }
+			set { SetValue(CollapsibleProperty, value); }
+		}
+
+		public static readonly DependencyProperty TreeParentProperty =
+			DependencyProperty.Register(
+				"TreeParent",
+				typeof(string),
+				typeof(TreeNode),
+				new PropertyMetadata(
+					null,
+					null
+				));
+
+		public static TreeNode GetParentElement(TreeNode tn)
+		{
+			BehaviorPanel tc;
+			TreeNode tnParent;
+
+			if (tn == null)
+			{
+				return null;
+			}
+			tc = tn.Parent as BehaviorPanel;
+			if (tc == null)
+			{
+				return null;
+			}
+			string strParent = tn.TreeParent;
+			if (strParent == null)
+			{
+				return null;
+			}
+
+			tnParent = tc.FindName(strParent) as TreeNode;
+			if (tnParent == null)
+			{
+				return null;
+			}
+			return tnParent;
+		}
+
+		public string TreeParent
+		{
+			get { return (string)GetValue(TreeParentProperty); }
+			set { SetValue(TreeParentProperty, value); }
+		}
+
+		public TreeNode()
+		{
+			TreeChildren = new TreeNodeGroup();
+			Background = new SolidColorBrush();
+		}
+
+		static TreeNode()
+		{
+		}
+
+		internal void ClearParent()
+		{
+			TreeChildren = new TreeNodeGroup();
+		}
+
+		internal bool SetParent()
+		{
+			TreeNode tn = GetParentElement(this);
+			if (tn == null)
+			{
+				return false;
+			}
+			tn.TreeChildren.Add(this);
+			return true;
+		}
+
+		public object PrivateNodeInfo { get; set; }
+
+		public TreeNodeGroup TreeChildren { get; private set; }
+
+		internal Size NodeSize()
+		{
+			return DesiredSize;
+		}
+
+		public double TreeHeight
+		{
+			get
+			{
+				return NodeSize().Height;
+			}
+		}
+
+		public double TreeWidth
+		{
+			get
+			{
+				return NodeSize().Width;
+			}
+		}
+	}
+}

+ 59 - 0
CSharp/Controls/BehaviorTree/TreeNodeGroup.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.ObjectModel;
+
+namespace BehaviorTree
+{
+	public class TreeNodeGroup : IEnumerable<ITreeNode>
+	{
+		Collection<ITreeNode> col = new Collection<ITreeNode>();
+
+		public int Count
+		{
+			get
+			{
+				return col.Count;
+			}
+		}
+
+		public ITreeNode this[int index]
+		{
+			get { return col[index]; }
+		}
+
+		public void Add(ITreeNode tn)
+		{
+			col.Add(tn);
+		}
+
+		internal ITreeNode LeftMost()
+		{
+			return col.First();
+		}
+
+		internal ITreeNode RightMost()
+		{
+			return col.Last();
+		}
+
+		#region IEnumerable<IGraphNode> Members
+
+		public IEnumerator<ITreeNode> GetEnumerator()
+		{
+			return col.GetEnumerator();
+		}
+
+		#endregion
+
+		#region IEnumerable Members
+
+		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+		{
+			return col.GetEnumerator();
+		}
+
+		#endregion
+	}
+}

+ 0 - 11
CSharp/Modules/TreeCanvas/Arrow.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace TreeCanvas
-{
-	class Arrow
-	{
-	}
-}

+ 0 - 11
CSharp/Modules/TreeCanvas/Connector.cs

@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace TreeCanvas
-{
-	class Connector
-	{
-	}
-}

+ 0 - 18
CSharp/Modules/TreeCanvas/Node.cs

@@ -1,18 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Windows;
-
-namespace TreeCanvas
-{
-	class Node
-	{
-		private Point point;
-
-		public Node(Point point)
-		{
-			this.point = point;
-		}
-	}
-}

+ 5 - 5
CSharp/Modules/TreeCanvas/Packages.config

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="CommonServiceLocator" version="1.0" />
-  <package id="Google.ProtocolBuffers" version="2.4.1.473" />
-  <package id="NLog" version="2.0.0.2000" />
-  <package id="Prism" version="4.0.0.0" />
-  <package id="Prism.MEFExtensions" version="4.0.0.0" />
+	<package id="CommonServiceLocator" version="1.0" />
+	<package id="Google.ProtocolBuffers" version="2.4.1.473" />
+	<package id="NLog" version="2.0.0.2000" />
+	<package id="Prism" version="4.0.0.0" />
+	<package id="Prism.MEFExtensions" version="4.0.0.0" />
 </packages>

+ 7 - 1
CSharp/Modules/TreeCanvas/Person.proto

@@ -1,8 +1,14 @@
-package Egametang;
+package TreeCanvas;
 
 import "google/protobuf/csharp_options.proto";
 
 message Person
 {
 	required int32 num = 1;
+	optional int32 age = 2;
+};
+
+message Group
+{
+	repeated Person persons = 1;
 };

+ 4 - 6
CSharp/Modules/TreeCanvas/TreeCanvas.csproj

@@ -68,9 +68,6 @@
     <Reference Include="WindowsBase" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Arrow.cs" />
-    <Compile Include="Connector.cs" />
-    <Compile Include="Node.cs" />
     <Compile Include="Person.pb.cs">
       <AutoGen>True</AutoGen>
       <DesignTime>True</DesignTime>
@@ -92,6 +89,10 @@
     </Page>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\..\Controls\BehaviorTree\BehaviorTree.csproj">
+      <Project>{88A0D086-1C51-466C-9123-793FFB5714B8}</Project>
+      <Name>BehaviorTree</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\Infrastructure\Infrastructure.csproj">
       <Project>{48A2E149-0DAC-41B4-BB54-DFBCCD6D42B3}</Project>
       <Name>Infrastructure</Name>
@@ -106,9 +107,6 @@
       <LastGenOutput>Person.pb.cs</LastGenOutput>
     </None>
   </ItemGroup>
-  <ItemGroup>
-    <Content Include="CHANGES.txt" />
-  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent>$(SolutionDir)\Tools\Nuget.exe install $(ProjectDir)Packages.config -o $(SolutionDir)Packages</PreBuildEvent>

+ 29 - 3
CSharp/Modules/TreeCanvas/TreeCanvasView.xaml

@@ -6,6 +6,7 @@
 		xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" 
 		xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
 		xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
+		xmlns:tc="clr-namespace:BehaviorTree;assembly=BehaviorTree"
 		x:Class="TreeCanvas.TreeCanvasView" 
 		mc:Ignorable="d" 
 		d:DesignHeight="600" d:DesignWidth="800">
@@ -21,8 +22,33 @@
 		</ContextMenu>
 	</UserControl.ContextMenu>
 
-	<Canvas Background="Transparent" Name="canvasTree">
+	<!--<Canvas Background="Transparent" Name="canvasTree">
 		
-	</Canvas>
-	
+	</Canvas>-->
+
+	<Grid x:Name="LayoutRoot" Background="White">
+		<Grid.RowDefinitions>
+			<RowDefinition Height="Auto"/>
+			<RowDefinition Height="Auto"/>
+		</Grid.RowDefinitions>
+		<Rectangle Stroke="{x:Null}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Fill="{x:Null}" Margin="0,0,0,0"/>
+		<tc:BehaviorPanel Root="O" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="tc" HorizontalBuffer="38" VerticalBuffer="48" HorizontalBufferSubtree="40" Margin="0,10,0,0">
+			<tc:TreeNode x:Name="O" Content="O"/>
+			<tc:TreeNode Content="E" TreeParent="O" x:Name="E" />
+			<tc:TreeNode Content="F" TreeParent="O" x:Name="F"/>
+			<tc:TreeNode Content="N" TreeParent="O" x:Name="N"/>
+			<tc:TreeNode Content="A" TreeParent="E" x:Name="A"/>
+			<tc:TreeNode Content="D" x:Name="D" TreeParent="E"/>
+			<tc:TreeNode Content="B" x:Name="B" TreeParent="D"/>
+			<tc:TreeNode Content="C" x:Name="C" TreeParent="D"/>
+			<tc:TreeNode Content="G" x:Name="G" TreeParent="N"/>
+			<tc:TreeNode Content="M" x:Name="M" TreeParent="N"/>
+			<tc:TreeNode Content="H" x:Name="H" TreeParent="M"/>
+			<tc:TreeNode Content="I" x:Name="I" TreeParent="M"/>
+			<tc:TreeNode Content="J" x:Name="J" TreeParent="M"/>
+			<tc:TreeNode Content="K" x:Name="K" TreeParent="M"/>
+			<tc:TreeNode Content="L" x:Name="L" TreeParent="M"/>
+		</tc:BehaviorPanel>
+		<Button HorizontalAlignment="Center" VerticalAlignment="Top" Content="Create Dynamically" Grid.Row="1" Margin="0,14,0,5" x:Name="btnDynamic" Click="btnDynamic_Click"/>
+	</Grid>
 </UserControl>

+ 83 - 2
CSharp/Modules/TreeCanvas/TreeCanvasView.xaml.cs

@@ -13,6 +13,7 @@ using System.Windows.Navigation;
 using System.Windows.Shapes;
 using System.ComponentModel.Composition;
 using Infrastructure;
+using BehaviorTree;
 
 namespace TreeCanvas
 {
@@ -43,8 +44,88 @@ namespace TreeCanvas
 
 		private void NewNode_Executed(object sender, ExecutedRoutedEventArgs e)
 		{
-			Point point = Mouse.GetPosition(canvasTree);
-			this.ViewModel.NewNode(point);
+
+		}
+
+		private void btnDynamic_Click(object sender, RoutedEventArgs e)
+		{
+			DrawDynamicTree();
+		}
+
+		private void DrawDynamicTree()
+		{
+			tc.Clear();
+			Button btnA = new Button();
+			Button btnB = new Button();
+			Button btnC = new Button();
+			Button btnD = new Button();
+			Button btnE = new Button();
+			Button btnF = new Button();
+			Button btnG = new Button();
+			Button btnH = new Button();
+			Button btnI = new Button();
+			Button btnJ = new Button();
+			Button btnK = new Button();
+			Button btnL = new Button();
+			Button btnM = new Button();
+			Button btnN = new Button();
+			Button btnO = new Button();
+			btnA.Content = "A";
+			btnB.Content = "B";
+			btnC.Content = "C";
+			btnD.Content = "D";
+			btnE.Content = "E";
+			btnF.Content = "F";
+			btnG.Content = "G";
+			btnH.Content = "H";
+			btnI.Content = "I";
+			btnJ.Content = "J";
+			btnK.Content = "K";
+			btnL.Content = "L";
+			btnM.Content = "M";
+			btnN.Content = "N";
+			btnO.Content = "O";
+			btnA.Click += new RoutedEventHandler(btn_Click);
+			btnB.Click += new RoutedEventHandler(btn_Click);
+			btnC.Click += new RoutedEventHandler(btn_Click);
+			btnD.Click += new RoutedEventHandler(btn_Click);
+			btnE.Click += new RoutedEventHandler(btn_Click);
+			btnF.Click += new RoutedEventHandler(btn_Click);
+			btnG.Click += new RoutedEventHandler(btn_Click);
+			btnH.Click += new RoutedEventHandler(btn_Click);
+			btnI.Click += new RoutedEventHandler(btn_Click);
+			btnJ.Click += new RoutedEventHandler(btn_Click);
+			btnK.Click += new RoutedEventHandler(btn_Click);
+			btnL.Click += new RoutedEventHandler(btn_Click);
+			btnM.Click += new RoutedEventHandler(btn_Click);
+			btnN.Click += new RoutedEventHandler(btn_Click);
+			btnO.Click += new RoutedEventHandler(btn_Click);
+
+			TreeNode tnSubtreeRootO = tc.AddRoot(btnO);
+			TreeNode tnSubtreeRootE = tc.AddNode(btnE, tnSubtreeRootO);
+			tc.AddNode(btnF, tnSubtreeRootO);
+			TreeNode tnSubtreeRootN = tc.AddNode(btnN, tnSubtreeRootO);
+			TreeNode tnSubtreeRootD = tc.AddNode(btnD, tnSubtreeRootE);
+			tc.AddNode(btnA, tnSubtreeRootE);
+			tc.AddNode(btnB, tnSubtreeRootD);
+			tc.AddNode(btnC, tnSubtreeRootD);
+			tc.AddNode(btnG, tnSubtreeRootN);
+			TreeNode tnSubtreeRootM = tc.AddNode(btnM, tnSubtreeRootN);
+			tc.AddNode(btnH, tnSubtreeRootM);
+			tc.AddNode(btnI, tnSubtreeRootM);
+			tc.AddNode(btnJ, tnSubtreeRootM);
+			tc.AddNode(btnK, tnSubtreeRootM);
+			tc.AddNode(btnL, tnSubtreeRootM);
+		}
+
+		private void btn_Click(object sender, RoutedEventArgs e)
+		{
+			Button btn = e.OriginalSource as Button;
+			if (btn != null)
+			{
+				TreeNode tn = (TreeNode)(btn.Parent);
+				tn.Collapsed = !tn.Collapsed;
+			}
 		}
 	}
 }

+ 0 - 38
CSharp/Modules/TreeCanvas/TreeCanvasViewModel.cs

@@ -13,44 +13,6 @@ namespace TreeCanvas
 	[PartCreationPolicy(CreationPolicy.NonShared)]
 	class TreeCanvasViewModel : NotificationObject
 	{
-		private Logger logger = LogManager.GetCurrentClassLogger();
-
-		private ObservableCollection<Node> nodes = new ObservableCollection<Node>();
-		private ObservableCollection<Arrow> arrows = new ObservableCollection<Arrow>();
-				
-		public TreeCanvasViewModel()
-		{
-			logger.Debug("TreeCanvasViewModel");
-		}
-
-		public ObservableCollection<Node> Nodes
-		{
-			get
-			{
-				return nodes;
-			}
-		}
-
-		public ObservableCollection<Arrow> Arrows
-		{
-			get
-			{
-				return arrows;
-			}
-		}
-
-		public void NewNode(Point point)
-		{
-			Nodes.Add(new Node(point));
-			Person.Builder personBuilder = Person.CreateBuilder();
-			personBuilder.SetNum(1);
-			Person person = personBuilder.Build();
-			string s = TextFormat.PrintToString(person);
-			logger.Debug(s);
-
-			TextFormat.Merge("num: 2", personBuilder);
-			Person person2 = personBuilder.Build();
-		}
 	}
 }
 

+ 0 - 4
CSharp/Tools/CmdTool.exe.config

@@ -13,11 +13,7 @@
 				<arg value="$(InputPath)"/>
 				<!-- protogen.exe arguments -->
 				<arg value="-file_extension=.pb.cs"/>
-				<arg value="-namespace=$(Namespace)"/>
 				<arg value="-output_directory=$(InputDir)\"/>
-				<arg value="-ignore_google_protobuf=true"/>
-				<arg value="-cls_compliance=false"/>
-				<arg value="-nest_classes=false"/>
 				<output extension=".pb.cs"/>
 			</generator>
 		</match>