类的结构图如下:
INode接口代码如下,其中最重要就是ToString方法了,它决定了如何呈现树。
1
/**/
/// <summary>
2 /// INode [实现先序遍历]
3 /// </summary>
4 public interface INode : System.Collections.Generic.IEnumerable < INode >
5 {
6 INode Parent { get;set;} //取得父结点
7 INodeList Childs { get; } //取得下级节点
8 INodeList Leafs { get;} //取得以该节点为根的子数的叶子节点
9 bool IsLeaf { get;} //是否为叶子结点
10
11 int Tier { get;} //取得该节点在树中的所处层数(从0开始计数)
12 int Depth { get;} //取得以该节点为根的子数的深度(本层为0)
13
14 IAttributeDictionary Attributes { get;set;} //该节点的属性集合
15
16 object Content { get;set;} //节点中的内容
17
18 children operation#region children operation
19
20 void AddChild(INode child);
21 bool RemoveChild(INode child);
22 void ClearChildren();
23
24 #endregion
25
26 string ToString(); //将节点和其属性以及内容表示为网页可显示的字符串
27
28
29 }
2 /// INode [实现先序遍历]
3 /// </summary>
4 public interface INode : System.Collections.Generic.IEnumerable < INode >
5 {
6 INode Parent { get;set;} //取得父结点
7 INodeList Childs { get; } //取得下级节点
8 INodeList Leafs { get;} //取得以该节点为根的子数的叶子节点
9 bool IsLeaf { get;} //是否为叶子结点
10
11 int Tier { get;} //取得该节点在树中的所处层数(从0开始计数)
12 int Depth { get;} //取得以该节点为根的子数的深度(本层为0)
13
14 IAttributeDictionary Attributes { get;set;} //该节点的属性集合
15
16 object Content { get;set;} //节点中的内容
17
18 children operation#region children operation
19
20 void AddChild(INode child);
21 bool RemoveChild(INode child);
22 void ClearChildren();
23
24 #endregion
25
26 string ToString(); //将节点和其属性以及内容表示为网页可显示的字符串
27
28
29 }
ITree接口如下,这个接口继承了INode,特别突出了下ToString方法,其作用是呈现整个树。为了将一个纵向的树横向的呈现,我们必须使用前根遍历该树的所有子节点,并依次调用子节点的ToString方法,并在遍历到叶子节点的时候加上“回车”(</tr>)以表示该html行结束。
注意到ITree在INode的基础上加上了一个FullFill的方法,该方法用于将一个非满树用空结点补满,否则表格就会出现缺格。其中T是指用于填充树的类型,也就是用何种INode来填满这颗树。当然这应该和你用来构建这颗树的节点类型一样。
1
/**/
/// <summary>
2 /// ITree 的摘要说明
3 /// </summary>
4 public interface ITree : INode
5 {
6 //ITree FullFill(); //返回该树的"满数"
7 ITree FullFill<T>() where T : INode, new(); //泛型版本(用类型T来填充)
8
9 new string ToString(); //1循环子节点 2调用INode的[前序遍历] 3调用INode.ToString(); 4每行开始<tr>、结束(遍历到叶子节点)加上</tr> 5加上<table></table>
10 }
2 /// ITree 的摘要说明
3 /// </summary>
4 public interface ITree : INode
5 {
6 //ITree FullFill(); //返回该树的"满数"
7 ITree FullFill<T>() where T : INode, new(); //泛型版本(用类型T来填充)
8
9 new string ToString(); //1循环子节点 2调用INode的[前序遍历] 3调用INode.ToString(); 4每行开始<tr>、结束(遍历到叶子节点)加上</tr> 5加上<table></table>
10 }
BaseNode是个模版类,其对添加和移除子节点时作了些额外控制,防止同一个INode对象添加到了2个或以上的父节点下:
1
/**/
/// <summary>
2 /// Node 的摘要说明
3 /// </summary>
4 public abstract class BaseNode : INode
5 {
6 protected INode parent; //父节点
7 protected IList<INode> childs = new List<INode>(); //子节点的"内部表现"
8
9 public BaseNode()
10 { }
11
12 public BaseNode(INode parent)
13 {
14 parent.AddChild(this);
15 this.parent = parent;
16 }
17
18 //private void initial()
19 //{
20
21 //}
22
23 INode 成员#region INode 成员
24
25 /**//// <summary>
26 /// 取得父结点
27 /// </summary>
28 public INode Parent
29 {
30 get { return this.parent; }
31 set
32 {
33 value.AddChild(this); //设定父节点的同时,在父节点的子列表中加入该结点
34 this.parent = value;
35 }
36 }
37
38 /**//// <summary>
39 /// 取得下级节点--子结点的外部表现(只读)
40 /// </summary>
41 public INodeList Childs
42 {
43 get { return new BaseNodeList(childs); }
44 }
45
46 /**//// <summary>
47 /// 取得以该节点为根的子数的叶子节点
48 /// </summary>
49 public INodeList Leafs
50 {
51 get
52 {
53 IList<INode> leafs = new List<INode>();
54 foreach (INode node in this)
55 {
56 //判断是否为叶子结点
57 if (node.Childs.Count == 0)
58 leafs.Add(node);
59 }
60 return new BaseNodeList(leafs);
61 }
62 }
63
64 /**//// <summary>
65 /// 是否是叶子结点
66 /// </summary>
67 public bool IsLeaf
68 {
69 get
70 {
71 if (this.childs.Count == 0)
72 return true;
73 return false;
74 }
75 }
76
77 /**//// <summary>
78 /// 取得该节点在树中的所处层数(从0开始计数)
79 /// </summary>
80 public int Tier
81 {
82 get { return this.getTier(this); }
83 }
84
85 /**//// <summary>
86 /// 取得以该节点为根的子数的深度(本层为0)
87 /// </summary>
88 public int Depth
89 {
90 get { return this.getDepth(this); }
91 }
92
93 抽象方法#region 抽象方法
94
95 /**//// <summary>
96 /// 属性列表(根据其ToString方法来显示)
97 /// </summary>
98 public abstract IAttributeDictionary Attributes { get;set;}
99
100 /**//// <summary>
101 /// 结点内容(可以是任何对象,最终根据INode.ToString方法来显示)
102 /// </summary>
103 public abstract object Content { get;set;}
104
105 /**//// <summary>
106 /// 必须重写ToString方法,用于呈现该INode
107 /// </summary>
108 /// <returns></returns>
109 public abstract override string ToString();
110
111 #endregion
112
113 操作子结点#region 操作子结点
114
115 /**//// <summary>
116 /// 添加一个子结点
117 /// </summary>
118 /// <param name="item"></param>
119 public void AddChild(INode item)
120 {
121 INode oldParent = item.Parent; //原父结点
122 if (oldParent == null || oldParent.RemoveChild(item)) //从原父节点的子结点中移除该结点
123 {
124 childs.Add(item);
125 //item.Parent = this; //该句会导致无限递归错误!
126 ((BaseNode)item).parent = this;
127 }
128 }
129
130 /**//// <summary>
131 /// 移除一个子结点
132 /// </summary>
133 /// <param name="item"></param>
134 /// <returns></returns>
135 public bool RemoveChild(INode item)
136 {
137 if (this.childs.Remove(item))
138 {
139 item.Parent = null;
140 return true;
141 }
142 return false;
143 }
144
145 /**//// <summary>
146 /// 清空子结点
147 /// </summary>
148 public void ClearChildren()
149 {
150 foreach (INode node in childs)
151 {
152 childs.Remove(node);
153 }
154 }
155
156 #endregion
157
158 #endregion
159
160 IEnumerable 成员#region IEnumerable<INode> 成员
161
162 /**//// <summary>
163 /// 先序遍历
164 /// </summary>
165 /// <returns></returns>
166 public IEnumerator<INode> GetEnumerator()
167 {
168 Queue<INode> queueList = new Queue<INode>(); //按序进出的队列
169 perOrderTraverse(queueList, this); //本身不入队列
170 while (queueList.Count > 0 && queueList.Peek() != null)
171 {
172 yield return queueList.Dequeue();
173 }
174 }
175
176 #endregion
177
178 IEnumerable 成员#region IEnumerable 成员
179
180 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
181 {
182 return GetEnumerator();
183 }
184
185 #endregion
186
187 /**//// <summary>
188 /// 先序遍历,并按序入队列
189 /// </summary>
190 private void perOrderTraverse(Queue<INode> queueList, INode parentNode)
191 {
192 foreach (INode node in parentNode.Childs)
193 {
194 queueList.Enqueue(node);
195 perOrderTraverse(queueList, node);
196 }
197 }
198
199 /**//// <summary>
200 /// 取得深度
201 /// </summary>
202 private int getDepth(INode node)
203 {
204 if (node == null || node.Childs.Count == 0)
205 return 0;
206
207 int[] childDepthArray = new int[node.Childs.Count];
208 INodeList childList = node.Childs;
209 for (int i = 0; i < childList.Count; i++)
210 {
211 childDepthArray[i] = getDepth(childList[i]);
212 }
213
214 Array.Sort<int>(childDepthArray); //升序排序
215 return childDepthArray[childDepthArray.Length - 1] + 1; //取得最大层数子树的层数 + 1
216 }
217
218 /**//// <summary>
219 /// 取得层数
220 /// </summary>
221 private int getTier(INode node)
222 {
223 int tier = 0;
224 INode n = node;
225 while (n.Parent != null)
226 {
227 n = n.Parent;
228 tier++;
229 }
230 return tier;
231 }
232 }
2 /// Node 的摘要说明
3 /// </summary>
4 public abstract class BaseNode : INode
5 {
6 protected INode parent; //父节点
7 protected IList<INode> childs = new List<INode>(); //子节点的"内部表现"
8
9 public BaseNode()
10 { }
11
12 public BaseNode(INode parent)
13 {
14 parent.AddChild(this);
15 this.parent = parent;
16 }
17
18 //private void initial()
19 //{
20
21 //}
22
23 INode 成员#region INode 成员
24
25 /**//// <summary>
26 /// 取得父结点
27 /// </summary>
28 public INode Parent
29 {
30 get { return this.parent; }
31 set
32 {
33 value.AddChild(this); //设定父节点的同时,在父节点的子列表中加入该结点
34 this.parent = value;
35 }
36 }
37
38 /**//// <summary>
39 /// 取得下级节点--子结点的外部表现(只读)
40 /// </summary>
41 public INodeList Childs
42 {
43 get { return new BaseNodeList(childs); }
44 }
45
46 /**//// <summary>
47 /// 取得以该节点为根的子数的叶子节点
48 /// </summary>
49 public INodeList Leafs
50 {
51 get
52 {
53 IList<INode> leafs = new List<INode>();
54 foreach (INode node in this)
55 {
56 //判断是否为叶子结点
57 if (node.Childs.Count == 0)
58 leafs.Add(node);
59 }
60 return new BaseNodeList(leafs);
61 }
62 }
63
64 /**//// <summary>
65 /// 是否是叶子结点
66 /// </summary>
67 public bool IsLeaf
68 {
69 get
70 {
71 if (this.childs.Count == 0)
72 return true;
73 return false;
74 }
75 }
76
77 /**//// <summary>
78 /// 取得该节点在树中的所处层数(从0开始计数)
79 /// </summary>
80 public int Tier
81 {
82 get { return this.getTier(this); }
83 }
84
85 /**//// <summary>
86 /// 取得以该节点为根的子数的深度(本层为0)
87 /// </summary>
88 public int Depth
89 {
90 get { return this.getDepth(this); }
91 }
92
93 抽象方法#region 抽象方法
94
95 /**//// <summary>
96 /// 属性列表(根据其ToString方法来显示)
97 /// </summary>
98 public abstract IAttributeDictionary Attributes { get;set;}
99
100 /**//// <summary>
101 /// 结点内容(可以是任何对象,最终根据INode.ToString方法来显示)
102 /// </summary>
103 public abstract object Content { get;set;}
104
105 /**//// <summary>
106 /// 必须重写ToString方法,用于呈现该INode
107 /// </summary>
108 /// <returns></returns>
109 public abstract override string ToString();
110
111 #endregion
112
113 操作子结点#region 操作子结点
114
115 /**//// <summary>
116 /// 添加一个子结点
117 /// </summary>
118 /// <param name="item"></param>
119 public void AddChild(INode item)
120 {
121 INode oldParent = item.Parent; //原父结点
122 if (oldParent == null || oldParent.RemoveChild(item)) //从原父节点的子结点中移除该结点
123 {
124 childs.Add(item);
125 //item.Parent = this; //该句会导致无限递归错误!
126 ((BaseNode)item).parent = this;
127 }
128 }
129
130 /**//// <summary>
131 /// 移除一个子结点
132 /// </summary>
133 /// <param name="item"></param>
134 /// <returns></returns>
135 public bool RemoveChild(INode item)
136 {
137 if (this.childs.Remove(item))
138 {
139 item.Parent = null;
140 return true;
141 }
142 return false;
143 }
144
145 /**//// <summary>
146 /// 清空子结点
147 /// </summary>
148 public void ClearChildren()
149 {
150 foreach (INode node in childs)
151 {
152 childs.Remove(node);
153 }
154 }
155
156 #endregion
157
158 #endregion
159
160 IEnumerable 成员#region IEnumerable<INode> 成员
161
162 /**//// <summary>
163 /// 先序遍历
164 /// </summary>
165 /// <returns></returns>
166 public IEnumerator<INode> GetEnumerator()
167 {
168 Queue<INode> queueList = new Queue<INode>(); //按序进出的队列
169 perOrderTraverse(queueList, this); //本身不入队列
170 while (queueList.Count > 0 && queueList.Peek() != null)
171 {
172 yield return queueList.Dequeue();
173 }
174 }
175
176 #endregion
177
178 IEnumerable 成员#region IEnumerable 成员
179
180 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
181 {
182 return GetEnumerator();
183 }
184
185 #endregion
186
187 /**//// <summary>
188 /// 先序遍历,并按序入队列
189 /// </summary>
190 private void perOrderTraverse(Queue<INode> queueList, INode parentNode)
191 {
192 foreach (INode node in parentNode.Childs)
193 {
194 queueList.Enqueue(node);
195 perOrderTraverse(queueList, node);
196 }
197 }
198
199 /**//// <summary>
200 /// 取得深度
201 /// </summary>
202 private int getDepth(INode node)
203 {
204 if (node == null || node.Childs.Count == 0)
205 return 0;
206
207 int[] childDepthArray = new int[node.Childs.Count];
208 INodeList childList = node.Childs;
209 for (int i = 0; i < childList.Count; i++)
210 {
211 childDepthArray[i] = getDepth(childList[i]);
212 }
213
214 Array.Sort<int>(childDepthArray); //升序排序
215 return childDepthArray[childDepthArray.Length - 1] + 1; //取得最大层数子树的层数 + 1
216 }
217
218 /**//// <summary>
219 /// 取得层数
220 /// </summary>
221 private int getTier(INode node)
222 {
223 int tier = 0;
224 INode n = node;
225 while (n.Parent != null)
226 {
227 n = n.Parent;
228 tier++;
229 }
230 return tier;
231 }
232 }
BaseTree是ITree的模版实现, 其中的关键在于如何计算每个节点的rowspan(只需要计算以该节点为根的子树有几个叶子节点,即表示该节点需要多少rowspan),并且这里的IEnumerator必须以前序遍历来返回所有子节点,原因之前已经提到过。
1
/**/
/// <summary>
2 /// Tree 的摘要说明
3 /// </summary>
4 public class BaseTree : BaseNode, ITree
5 {
6 protected IAttributeDictionary attributes = new BaseAttributeDictionary(); //属性集合
7
8 ITree 成员#region ITree 成员
9
10 /**////// <summary>
11 ///// 返回该树的"满数"
12 ///// </summary>
13 ///// <returns></returns>
14 //public virtual ITree FullFill()
15 //{
16 // int treeHeight = this.Depth; //该树的高度
17 // INodeList leafs = this.Leafs; //该树的叶子集合
18 // foreach (INode node in leafs)
19 // {
20 // int tier = node.Tier; //某叶子结点的所在层数
21 // if (tier < treeHeight)//填到树的高度
22 // {
23 // int length = treeHeight - tier; //需要填充的高度
24 // this.addFixLengthNode(length, node);
25 // }
26 // }
27 // return this;
28 //}
29
30 /**//// <summary>
31 /// 返回该树的"满数"(用T类型的结点填充)
32 /// </summary>
33 /// <returns></returns>
34 public virtual ITree FullFill<T>() where T : INode, new()
35 {
36 int treeHeight = this.Depth; //该树的高度
37 INodeList leafs = this.Leafs; //该树的叶子集合
38 foreach (INode node in leafs)
39 {
40 int tier = node.Tier; //某叶子结点的所在层数
41 if (tier < treeHeight)//填到树的高度
42 {
43 int length = treeHeight - tier; //需要填充的高度
44 this.addFixLengthNode<T>(length, node);
45 }
46 }
47 return this;
48 }
49
50 #endregion
51
52 IEnumerable 成员#region IEnumerable 成员
53
54 public new IEnumerator GetEnumerator()
55 {
56 return base.GetEnumerator();
57 }
58
59 #endregion
60
61 public override IAttributeDictionary Attributes
62 {
63 get { return this.attributes; }
64 set { this.attributes = value; }
65 }
66
67 public override object Content
68 {
69 get { return this.ToString(); }
70 set { new Exception("不可更改内容"); }
71 }
72
73 /**//// <summary>
74 /// 1循环子节点
75 /// 2调用INode的[前序遍历]
76 /// 3调用INode.ToString();
77 /// 4每行开始<tr>、结束(遍历到叶子节点)加上<![CDATA[</tr> ]]>
78 /// 5加上<![CDATA[<table></table>]]>
79 /// </summary>
80 /// <returns></returns>
81 public override string ToString()
82 {
83 System.Text.StringBuilder builder = new System.Text.StringBuilder();
84 builder.Append("<table ").Append(this.attributes == null ? "" : this.attributes.ToString()).Append(">"); //加上table的属性
85 //多根循环
86 //foreach (INode rootNode in this.Childs)
87 {
88 builder.Append(@"<tr>");
89 foreach (INode node in this) //前序遍历
90 {
91 //加上rowspan属性
92 countRowSpan(node);
93
94 builder.Append(node.ToString());
95 if (node.IsLeaf)
96 {
97 builder.Append(@"</tr><tr>");
98 }
99 }
100 builder.Remove(builder.Length - 4, 4); //移除最后的<tr>
101 }
102 builder.Append(@"</table>");
103 return builder.ToString();
104 }
105
106 /**//// <summary>
107 /// 计算td的rowspan,并加上rowspan属性
108 /// </summary>
109 /// <param name="node">原结点</param>
110 protected virtual void countRowSpan(INode node)
111 {
112 int value = node.Leafs.Count; //计算叶子结点(rowspan的值)
113 if (node.Attributes == null)
114 {
115 node.Attributes = new BaseAttributeDictionary();
116 }
117 IAttri attri = new SingletonAttri("rowspan", value.ToString());
118 node.Attributes.Add(attri); //加上rowspan属性
119 }
120
121 /**////// <summary>
122 ///// 填充固定长度线性树
123 ///// </summary>
124 //private void addFixLengthNode(int length, INode parent)
125 //{
126 // if (length < 1)
127 // throw new Exception("无效长度,必须大于1");
128
129 // INode node = new SingletonNode(parent, " "); //空节点
130 // for (int i = 0; i < length - 1; i++)
131 // {
132 // INode tempNode = new SingletonNode(" "); //空节点
133 // node.AddChild(tempNode);
134 // node = tempNode; //持有下一个节点
135 // }
136 //}
137
138 /**//// <summary>
139 /// 填充固定长度线性树(用类型T填充)
140 /// </summary>
141 private void addFixLengthNode<T>(int length, INode parent) where T : INode, new()
142 {
143 if (length < 1)
144 throw new Exception("无效长度,必须大于1");
145
146 INode node = new T(); //空节点
147 node.Parent = parent;
148 node.Content = " ";
149
150 for (int i = 0; i < length - 1; i++)
151 {
152 INode tempNode = new T(); //空节点
153 tempNode.Content = " ";
154
155 node.AddChild(tempNode);
156 node = tempNode; //持有下一个节点
157 }
158 }
159 }
2 /// Tree 的摘要说明
3 /// </summary>
4 public class BaseTree : BaseNode, ITree
5 {
6 protected IAttributeDictionary attributes = new BaseAttributeDictionary(); //属性集合
7
8 ITree 成员#region ITree 成员
9
10 /**////// <summary>
11 ///// 返回该树的"满数"
12 ///// </summary>
13 ///// <returns></returns>
14 //public virtual ITree FullFill()
15 //{
16 // int treeHeight = this.Depth; //该树的高度
17 // INodeList leafs = this.Leafs; //该树的叶子集合
18 // foreach (INode node in leafs)
19 // {
20 // int tier = node.Tier; //某叶子结点的所在层数
21 // if (tier < treeHeight)//填到树的高度
22 // {
23 // int length = treeHeight - tier; //需要填充的高度
24 // this.addFixLengthNode(length, node);
25 // }
26 // }
27 // return this;
28 //}
29
30 /**//// <summary>
31 /// 返回该树的"满数"(用T类型的结点填充)
32 /// </summary>
33 /// <returns></returns>
34 public virtual ITree FullFill<T>() where T : INode, new()
35 {
36 int treeHeight = this.Depth; //该树的高度
37 INodeList leafs = this.Leafs; //该树的叶子集合
38 foreach (INode node in leafs)
39 {
40 int tier = node.Tier; //某叶子结点的所在层数
41 if (tier < treeHeight)//填到树的高度
42 {
43 int length = treeHeight - tier; //需要填充的高度
44 this.addFixLengthNode<T>(length, node);
45 }
46 }
47 return this;
48 }
49
50 #endregion
51
52 IEnumerable 成员#region IEnumerable 成员
53
54 public new IEnumerator GetEnumerator()
55 {
56 return base.GetEnumerator();
57 }
58
59 #endregion
60
61 public override IAttributeDictionary Attributes
62 {
63 get { return this.attributes; }
64 set { this.attributes = value; }
65 }
66
67 public override object Content
68 {
69 get { return this.ToString(); }
70 set { new Exception("不可更改内容"); }
71 }
72
73 /**//// <summary>
74 /// 1循环子节点
75 /// 2调用INode的[前序遍历]
76 /// 3调用INode.ToString();
77 /// 4每行开始<tr>、结束(遍历到叶子节点)加上<![CDATA[</tr> ]]>
78 /// 5加上<![CDATA[<table></table>]]>
79 /// </summary>
80 /// <returns></returns>
81 public override string ToString()
82 {
83 System.Text.StringBuilder builder = new System.Text.StringBuilder();
84 builder.Append("<table ").Append(this.attributes == null ? "" : this.attributes.ToString()).Append(">"); //加上table的属性
85 //多根循环
86 //foreach (INode rootNode in this.Childs)
87 {
88 builder.Append(@"<tr>");
89 foreach (INode node in this) //前序遍历
90 {
91 //加上rowspan属性
92 countRowSpan(node);
93
94 builder.Append(node.ToString());
95 if (node.IsLeaf)
96 {
97 builder.Append(@"</tr><tr>");
98 }
99 }
100 builder.Remove(builder.Length - 4, 4); //移除最后的<tr>
101 }
102 builder.Append(@"</table>");
103 return builder.ToString();
104 }
105
106 /**//// <summary>
107 /// 计算td的rowspan,并加上rowspan属性
108 /// </summary>
109 /// <param name="node">原结点</param>
110 protected virtual void countRowSpan(INode node)
111 {
112 int value = node.Leafs.Count; //计算叶子结点(rowspan的值)
113 if (node.Attributes == null)
114 {
115 node.Attributes = new BaseAttributeDictionary();
116 }
117 IAttri attri = new SingletonAttri("rowspan", value.ToString());
118 node.Attributes.Add(attri); //加上rowspan属性
119 }
120
121 /**////// <summary>
122 ///// 填充固定长度线性树
123 ///// </summary>
124 //private void addFixLengthNode(int length, INode parent)
125 //{
126 // if (length < 1)
127 // throw new Exception("无效长度,必须大于1");
128
129 // INode node = new SingletonNode(parent, " "); //空节点
130 // for (int i = 0; i < length - 1; i++)
131 // {
132 // INode tempNode = new SingletonNode(" "); //空节点
133 // node.AddChild(tempNode);
134 // node = tempNode; //持有下一个节点
135 // }
136 //}
137
138 /**//// <summary>
139 /// 填充固定长度线性树(用类型T填充)
140 /// </summary>
141 private void addFixLengthNode<T>(int length, INode parent) where T : INode, new()
142 {
143 if (length < 1)
144 throw new Exception("无效长度,必须大于1");
145
146 INode node = new T(); //空节点
147 node.Parent = parent;
148 node.Content = " ";
149
150 for (int i = 0; i < length - 1; i++)
151 {
152 INode tempNode = new T(); //空节点
153 tempNode.Content = " ";
154
155 node.AddChild(tempNode);
156 node = tempNode; //持有下一个节点
157 }
158 }
159 }
最后就是节点的具体实现了, SingletonNode是单td树节点:
1
/**/
/// <summary>
2 /// SingletonNode -- 单td树结点
3 /// </summary>
4 public class SingletonNode : BaseNode
5 {
6 private string content; //td中的内容
7 private IAttributeDictionary attributes = new BaseAttributeDictionary(); //td中的属性集合
8
9 构造器#region 构造器
10
11 public SingletonNode()
12 { }
13
14 public SingletonNode(string content)
15 {
16 this.content = content;
17 }
18
19 public SingletonNode(INode parent, string content)
20 : base(parent)
21 {
22 this.content = content;
23 }
24
25 public SingletonNode(INode parent, string content, IAttributeDictionary attributes)
26 : this(parent, content)
27 {
28 this.attributes = attributes; //属性列表
29 }
30
31 #endregion
32
33 public override IAttributeDictionary Attributes
34 {
35 get
36 {
37 return this.attributes;
38 }
39 set
40 {
41 this.attributes = value;
42 }
43 }
44
45 public override object Content
46 {
47 get
48 {
49 return this.content;
50 }
51 set
52 {
53 this.content = value.ToString();
54 }
55 }
56
57 public override string ToString()
58 {
59 System.Text.StringBuilder builder = new System.Text.StringBuilder();
60
61 string attriStr = attributes.ToString(); //属性
62
63 string showContent = this.content;
64 if (string.IsNullOrEmpty(content))
65 showContent = " "; //若该td中内容为空则需要显示一个空格,否则该td会显示不出来
66
67 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(showContent).Append(@"</td>");
68 return builder.ToString();
69 }
70
71 }
2 /// SingletonNode -- 单td树结点
3 /// </summary>
4 public class SingletonNode : BaseNode
5 {
6 private string content; //td中的内容
7 private IAttributeDictionary attributes = new BaseAttributeDictionary(); //td中的属性集合
8
9 构造器#region 构造器
10
11 public SingletonNode()
12 { }
13
14 public SingletonNode(string content)
15 {
16 this.content = content;
17 }
18
19 public SingletonNode(INode parent, string content)
20 : base(parent)
21 {
22 this.content = content;
23 }
24
25 public SingletonNode(INode parent, string content, IAttributeDictionary attributes)
26 : this(parent, content)
27 {
28 this.attributes = attributes; //属性列表
29 }
30
31 #endregion
32
33 public override IAttributeDictionary Attributes
34 {
35 get
36 {
37 return this.attributes;
38 }
39 set
40 {
41 this.attributes = value;
42 }
43 }
44
45 public override object Content
46 {
47 get
48 {
49 return this.content;
50 }
51 set
52 {
53 this.content = value.ToString();
54 }
55 }
56
57 public override string ToString()
58 {
59 System.Text.StringBuilder builder = new System.Text.StringBuilder();
60
61 string attriStr = attributes.ToString(); //属性
62
63 string showContent = this.content;
64 if (string.IsNullOrEmpty(content))
65 showContent = " "; //若该td中内容为空则需要显示一个空格,否则该td会显示不出来
66
67 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(showContent).Append(@"</td>");
68 return builder.ToString();
69 }
70
71 }
而 ContainIndexNode是带index的双td树节点:
1
/**/
/// <summary>
2 /// ContainIndexNode 包含index的结点
3 /// </summary>
4 public class ContainIndexNode : BaseNode
5 {
6 private string content; //td2中的内容
7 private IAttributeDictionary attributes = new BaseAttributeDictionary(); //td中的属性集合
8
9 构造器#region 构造器
10 public ContainIndexNode()
11 { }
12
13 public ContainIndexNode(string content)
14 {
15 this.content = content;
16 }
17
18 public ContainIndexNode(INode parent, string content)
19 : base(parent)
20 {
21 this.content = content;
22 }
23
24 public ContainIndexNode(INode parent, string content, IAttributeDictionary attributes)
25 : this(parent, content)
26 {
27 this.attributes = attributes; //属性列表
28 }
29
30 #endregion
31
32 public override IAttributeDictionary Attributes
33 {
34 get
35 {
36 return this.attributes;
37 }
38 set
39 {
40 this.attributes = value;
41 }
42 }
43
44 public override object Content
45 {
46 get
47 {
48 return this.content;
49 }
50 set
51 {
52 this.content = value.ToString();
53 }
54 }
55
56 public override string ToString()
57 {
58 System.Text.StringBuilder builder = new System.Text.StringBuilder();
59
60 string attriStr = attributes.ToString(); //属性
61
62 string showContent = this.content;
63 if (string.IsNullOrEmpty(content))
64 showContent = " "; //若该td中内容为空则需要显示一个空格,否则该td会显示不出来
65
66 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(this.getIndex()).Append(@"</td>");
67 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(showContent).Append(@"</td>");
68 return builder.ToString();
69 }
70
71 取得索引#region 取得索引
72
73 private string getIndex()
74 {
75 System.Text.StringBuilder builder = new System.Text.StringBuilder();
76 System.Collections.Generic.Stack<int> stack = new System.Collections.Generic.Stack<int>();
77 int parts = this.Tier;
78 int index = 0;
79
80 INode node = this;
81 while (index < parts)
82 {
83 int num = this.getIndex(node);
84 stack.Push(num);
85 node = node.Parent;
86
87 index++;
88 }
89
90 while (stack.Count > 0)
91 {
92 builder.Append(stack.Pop()).Append(".");
93 }
94
95 builder.Remove(builder.Length - 1, 1); //移除最后的点
96 return builder.ToString();
97 }
98
99 private int getIndex(INode node)
100 {
101 INodeList list = node.Parent.Childs;
102 for (int i = 0; i < list.Count; i++)
103 {
104 if (list[i] == node)
105 return i + 1;
106 }
107 return 0;
108 }
109
110 #endregion
111 }
只需要将注意力集中在单个内容对象Content的呈现方式上就可以了。2 /// ContainIndexNode 包含index的结点
3 /// </summary>
4 public class ContainIndexNode : BaseNode
5 {
6 private string content; //td2中的内容
7 private IAttributeDictionary attributes = new BaseAttributeDictionary(); //td中的属性集合
8
9 构造器#region 构造器
10 public ContainIndexNode()
11 { }
12
13 public ContainIndexNode(string content)
14 {
15 this.content = content;
16 }
17
18 public ContainIndexNode(INode parent, string content)
19 : base(parent)
20 {
21 this.content = content;
22 }
23
24 public ContainIndexNode(INode parent, string content, IAttributeDictionary attributes)
25 : this(parent, content)
26 {
27 this.attributes = attributes; //属性列表
28 }
29
30 #endregion
31
32 public override IAttributeDictionary Attributes
33 {
34 get
35 {
36 return this.attributes;
37 }
38 set
39 {
40 this.attributes = value;
41 }
42 }
43
44 public override object Content
45 {
46 get
47 {
48 return this.content;
49 }
50 set
51 {
52 this.content = value.ToString();
53 }
54 }
55
56 public override string ToString()
57 {
58 System.Text.StringBuilder builder = new System.Text.StringBuilder();
59
60 string attriStr = attributes.ToString(); //属性
61
62 string showContent = this.content;
63 if (string.IsNullOrEmpty(content))
64 showContent = " "; //若该td中内容为空则需要显示一个空格,否则该td会显示不出来
65
66 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(this.getIndex()).Append(@"</td>");
67 builder.Append(@"<td ").Append(attriStr).Append(@">").Append(showContent).Append(@"</td>");
68 return builder.ToString();
69 }
70
71 取得索引#region 取得索引
72
73 private string getIndex()
74 {
75 System.Text.StringBuilder builder = new System.Text.StringBuilder();
76 System.Collections.Generic.Stack<int> stack = new System.Collections.Generic.Stack<int>();
77 int parts = this.Tier;
78 int index = 0;
79
80 INode node = this;
81 while (index < parts)
82 {
83 int num = this.getIndex(node);
84 stack.Push(num);
85 node = node.Parent;
86
87 index++;
88 }
89
90 while (stack.Count > 0)
91 {
92 builder.Append(stack.Pop()).Append(".");
93 }
94
95 builder.Remove(builder.Length - 1, 1); //移除最后的点
96 return builder.ToString();
97 }
98
99 private int getIndex(INode node)
100 {
101 INodeList list = node.Parent.Childs;
102 for (int i = 0; i < list.Count; i++)
103 {
104 if (list[i] == node)
105 return i + 1;
106 }
107 return 0;
108 }
109
110 #endregion
111 }
其他有关INode集合以及html标签属性的接口和类的实现这里就不贴出来了,大家如果有兴趣可以下载源代码看下。
好了,赶快建个页面看下效果吧 ^_^
1
public
partial
class
_Default : System.Web.UI.Page
2 {
3 protected void Page_Load(object sender, EventArgs e)
4 {
5 BaseTree tree = new BaseTree();
6
7 build node#region build node
8 INode node0 = nodeFactory("node0");
9 INode node1 = nodeFactory("node1");
10 INode node2 = nodeFactory("node2");
11 INode node3 = nodeFactory("node3");
12 INode node4 = nodeFactory("node4");
13 INode node5 = nodeFactory("node5");
14 INode node6 = nodeFactory("node6");
15 INode node7 = nodeFactory("node7");
16 INode node8 = nodeFactory("node8");
17 INode node9 = nodeFactory(null);
18
19 tree.AddChild(node0);
20 tree.Attributes.Add(new SingletonAttri("border", "1px"));
21
22 node0.AddChild(node1);
23 node0.AddChild(node2);
24 node0.AddChild(node3);
25
26 node1.AddChild(node4);
27 node2.AddChild(node5);
28 node2.AddChild(node6);
29
30 node3.AddChild(node9);
31 node6.AddChild(node7);
32 node7.AddChild(node8);
33
34 node7.Attributes.Add(new SingletonAttri("bgcolor", "#FFE0D1"));
35
36 node8.AddChild(nodeFactory("node10"));
37 node2.AddChild(nodeFactory("node11"));
38 node7.AddChild(nodeFactory("node12"));
39 INode node13 = nodeFactory("node13");
40 node6.AddChild(node13);
41
42 INode node15 = nodeFactory("node15");
43 INode node14 = nodeFactory("node14");
44 tree.AddChild(node15);
45 node15.AddChild(node14);
46 node15.AddChild(nodeFactory("node17"));
47 node14.AddChild(nodeFactory("node16"));
48
49 node13.Attributes.Add(new SingletonAttri("onclick", "window.alert('ok');"));
50 #endregion
51
52 //填充树
53 tree.FullFill<SingletonNode>(); //单td的
54 //tree.FullFill<ContainIndexNode>(); //带index的双td节点表
55
56 string html = tree.ToString();
57 this.div1.InnerHtml = html;
58 }
59
60 private INode nodeFactory(string content)
61 {
62 return new SingletonNode(content); //单td的
63 //return new ContainIndexNode(content); //带index的双td节点表
64 }
65}
2 {
3 protected void Page_Load(object sender, EventArgs e)
4 {
5 BaseTree tree = new BaseTree();
6
7 build node#region build node
8 INode node0 = nodeFactory("node0");
9 INode node1 = nodeFactory("node1");
10 INode node2 = nodeFactory("node2");
11 INode node3 = nodeFactory("node3");
12 INode node4 = nodeFactory("node4");
13 INode node5 = nodeFactory("node5");
14 INode node6 = nodeFactory("node6");
15 INode node7 = nodeFactory("node7");
16 INode node8 = nodeFactory("node8");
17 INode node9 = nodeFactory(null);
18
19 tree.AddChild(node0);
20 tree.Attributes.Add(new SingletonAttri("border", "1px"));
21
22 node0.AddChild(node1);
23 node0.AddChild(node2);
24 node0.AddChild(node3);
25
26 node1.AddChild(node4);
27 node2.AddChild(node5);
28 node2.AddChild(node6);
29
30 node3.AddChild(node9);
31 node6.AddChild(node7);
32 node7.AddChild(node8);
33
34 node7.Attributes.Add(new SingletonAttri("bgcolor", "#FFE0D1"));
35
36 node8.AddChild(nodeFactory("node10"));
37 node2.AddChild(nodeFactory("node11"));
38 node7.AddChild(nodeFactory("node12"));
39 INode node13 = nodeFactory("node13");
40 node6.AddChild(node13);
41
42 INode node15 = nodeFactory("node15");
43 INode node14 = nodeFactory("node14");
44 tree.AddChild(node15);
45 node15.AddChild(node14);
46 node15.AddChild(nodeFactory("node17"));
47 node14.AddChild(nodeFactory("node16"));
48
49 node13.Attributes.Add(new SingletonAttri("onclick", "window.alert('ok');"));
50 #endregion
51
52 //填充树
53 tree.FullFill<SingletonNode>(); //单td的
54 //tree.FullFill<ContainIndexNode>(); //带index的双td节点表
55
56 string html = tree.ToString();
57 this.div1.InnerHtml = html;
58 }
59
60 private INode nodeFactory(string content)
61 {
62 return new SingletonNode(content); //单td的
63 //return new ContainIndexNode(content); //带index的双td节点表
64 }
65}
效果分别如下图:
第一次写 blog,如果写的不好请大家见谅
TreeTable源代码