Silverlight多重表头实现
Posted 小神仙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Silverlight多重表头实现相关的知识,希望对你有一定的参考价值。
效果:
实现主要逻辑:通过动态拼接XML生成表头样式,绑定到列上。
主要是动态拼接XML时要仔细核对对应的占位行,具体可以看代码,注释很详细
两个类一个接口
NTree<T>:定义表头树形结构
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Collections.ObjectModel; 5 6 namespace SLDGHeader 7 { 8 /// <summary> 9 /// 树结构 10 /// </summary> 11 /// <typeparam name="T">节点中的数据</typeparam> 12 public class NTree<T> 13 { 14 /// <summary> 15 /// 节点数据 16 /// </summary> 17 private readonly T data; 18 /// <summary> 19 /// 节点数据 20 /// </summary> 21 public T Data 22 { 23 get { return data; } 24 } 25 /// <summary> 26 /// 是否根节点 27 /// </summary> 28 public bool IsRoot { get { return Parent == null; } } 29 /// <summary> 30 /// 当前节点深度 31 /// 根节点为1 32 /// </summary> 33 public int Depth { get; private set; } 34 /// <summary> 35 /// 父节点 36 /// </summary> 37 public NTree<T> Parent 38 { 39 get; 40 private set; 41 } 42 /// <summary> 43 /// 子节点 44 /// </summary> 45 public ReadOnlyCollection<NTree<T>> Children 46 { 47 get { return children.AsReadOnly(); } 48 } 49 private List<NTree<T>> children; 50 /// <summary> 51 /// 实例化一个节点 52 /// </summary> 53 /// <param name="data">节点数据</param> 54 public NTree(T data) 55 { 56 this.Depth = 1; 57 this.data = data; 58 children = new List<NTree<T>>(); 59 } 60 /// <summary> 61 /// 在当前节点添加子节点 62 /// </summary> 63 /// <param name="data">节点数据</param> 64 /// <returns>当前节点</returns> 65 public NTree<T> AddChild(T data) 66 { 67 var node = new NTree<T>(data) { Parent = this, Depth = this.Depth + 1 }; 68 children.Add(node); 69 return this; 70 } 71 /// <summary> 72 /// 在当前节点子节点中插入子节点 73 /// </summary> 74 /// <param name="index">插入位置</param> 75 /// <param name="data">节点数据</param> 76 /// <returns>当前节点</returns> 77 public NTree<T> InsertChild(int index, T data) 78 { 79 var node = new NTree<T>(data) { Parent = this, Depth = this.Depth + 1 }; 80 children.Insert(index, node); 81 return this; 82 } 83 /// <summary> 84 /// 在当前节点添加子节点 85 /// </summary> 86 /// <param name="data">节点数据</param> 87 /// <returns>当前节点</returns> 88 public NTree<T> AddChilren(params T[] datas) 89 { 90 foreach (var data in datas) 91 { 92 AddChild(data); 93 } 94 return this; 95 } 96 /// <summary> 97 /// 移除当前节点下指定的子节点 98 /// </summary> 99 /// <param name="node">要移除的子节点</param> 100 /// <returns>当前节点</returns> 101 public NTree<T> RemoveChild(NTree<T> node) 102 { 103 children.Remove(node); 104 return this; 105 } 106 /// <summary> 107 /// 在当前节点添加兄弟节点 108 /// </summary> 109 /// <param name="data">节点数据</param> 110 /// <returns>当前节点</returns> 111 /// <exception cref="NullParentNodeException:当前节点没有父节点">当前节点没有父节点</exception> 112 public NTree<T> AddBrother(T data) 113 { 114 if (this.Parent == null) 115 { 116 throw new NullParentNodeException("有父节点的节点才能添加兄弟节点。"); 117 } 118 119 this.Parent.AddChild(data); 120 return this; 121 } 122 /// <summary> 123 /// 获取指定索引处的子节点 124 /// </summary> 125 /// <param name="i">子节点索引</param> 126 /// <returns>子节点</returns> 127 /// <exception cref="ArgumentOutOfRangeException:子节点索引超出范围">子节点索引超出范围</exception> 128 public NTree<T> GetChild(int i) 129 { 130 if (i >= children.Count || i < 0) 131 { 132 throw new ArgumentOutOfRangeException("子节点索引超出范围"); 133 } 134 return children[i]; 135 } 136 /// <summary> 137 /// 获取指定的子节点 138 /// </summary> 139 /// <param name="data">节点数据</param> 140 /// <returns>查找到的第一个子节点</returns> 141 public NTree<T> GetChild(T data) 142 { 143 return children.Where(i => i.data.Equals(data)).FirstOrDefault(); 144 } 145 /// <summary> 146 /// 获取指定子节点的索引 147 /// </summary> 148 /// <param name="data">节点数据</param> 149 /// <returns>查找到的第一个子节点的索引,没有找到返回-1</returns> 150 public int GetChildIndex(NTree<T> data) 151 { 152 var index = -1; 153 for (int i = 0; i < children.Count; i++) 154 { 155 if (children[i].Equals(data)) 156 { 157 index = i; 158 break; 159 } 160 } 161 return index; 162 } 163 /// <summary> 164 /// 遍历树节点 165 /// </summary> 166 /// <param name="node">起始节点</param> 167 /// <param name="action">遍历到每个节点的操作</param> 168 /// <exception cref="ArgumentNullException:参数action不可为空">参数action不可为空</exception> 169 public static void Traverse(NTree<T> node, Action<T> action) 170 { 171 if (action == null) 172 { 173 throw new ArgumentNullException("参数action不可为空"); 174 } 175 action(node.data); 176 foreach (var kid in node.children) 177 { 178 Traverse(kid, action); 179 } 180 } 181 /// <summary> 182 /// 从当前节点开始遍历树节点 183 /// </summary> 184 /// <param name="action">遍历到每个节点的操作</param> 185 /// <exception cref="ArgumentNullException:参数action不可为空">参数action不可为空</exception> 186 public void Traverse(Action<T> action) 187 { 188 Traverse(this, action); 189 } 190 /// <summary> 191 /// 遍历树节点 192 /// </summary> 193 /// <param name="node">起始节点</param> 194 /// <param name="action">遍历到每个节点的操作</param> 195 /// <exception cref="ArgumentNullException:参数action不可为空">参数action不可为空</exception> 196 public static void Traverse(NTree<T> node, Action<NTree<T>> action) 197 { 198 if (action == null) 199 { 200 throw new ArgumentNullException("参数action不可为空"); 201 } 202 action(node); 203 foreach (var kid in node.children) 204 { 205 Traverse(kid, action); 206 } 207 } 208 /// <summary> 209 /// 从当前节点开始遍历树节点 210 /// </summary> 211 /// <param name="action">遍历到每个节点的操作</param> 212 /// <exception cref="ArgumentNullException:参数action不可为空">参数action不可为空</exception> 213 public void Traverse(Action<NTree<T>> action) 214 { 215 if (action == null) 216 { 217 throw new ArgumentNullException("参数action不可为空"); 218 } 219 action(this); 220 foreach (var kid in this.children) 221 { 222 Traverse(kid, action); 223 } 224 } 225 /// <summary> 226 /// 获取当前节点开始的所有节点中数据 227 /// </summary> 228 /// <returns>节点数据列表</returns> 229 public IEnumerable<T> GetDatas() 230 { 231 return new[] { data }.Union(children.SelectMany(x => x.GetDatas())); 232 } 233 /// <summary> 234 /// 当前节点下叶节点的数量 235 /// </summary> 236 /// <returns></returns> 237 public int GetCount() 238 { 239 var count = 0; 240 Traverse((NTree<T> n) => 241 { 242 if (n.Children.Count == 0) 243 { 244 count++; 245 } 246 }); 247 return count; 248 } 249 /// <summary> 250 /// 获取当前节点所在树的深度 251 /// </summary> 252 /// <returns>当前节点所在树的深度</returns> 253 public int GetTreeDepth() 254 { 255 int Depth = 1; 256 var parent = this; 257 while (parent.Parent != null) 258 { 259 parent = parent.Parent; 260 } 261 Traverse((NTree<T> n) => 262 { 263 if (Depth < n.Depth) 264 { 265 Depth = n.Depth; 266 } 267 }); 268 269 return Depth; 270 } 271 } 272 /// <summary> 273 /// 父节点为空引用异常 274 /// </summary> 275 public class NullParentNodeException : Exception 276 { 277 public NullParentNodeException() 278 : base("父节点为空引用") 279 { 280 281 } 282 public NullParentNodeException(string message) 283 : base(message) 284 { 285 286 } 287 public NullParentNodeException(string message, Exception inner) 288 : base(message) 289 { 290 291 } 292 //public NullParentNodeException(SerializationInfo info, StreamingContext context) 293 //{ 294 295 //} 296 } 297 }
MultiHeadersColumn:多重表头和绑定的列
IDataGridHeader:定义生成表头和绑定列的数据接口
1 using System; 2 using System.Windows; 3 using System.Windows.Controls; 4 using System.Collections.Generic; 5 using System.Windows.Markup; 6 using System.Text; 7 8 namespace SLDGHeader 9 { 10 public class MultiHeadersColumn 11 { 12 #region 字段 13 /// <summary> 14 /// 单元格边框颜色 15 /// </summary> 16 string splitLineColor = "#ccc"; 17 /// <summary> 18 /// 数据行宽度 19 /// </summary> 20 string dataWidth = "30"; 21 /// <summary> 22 /// 表头行高度 23 /// </summary> 24 string dataHeight = "auto"; 25 /// <summary> 26 /// 分隔线线宽度 27 /// </summary> 28 string lineWidth = "1"; 29 /// <summary> 30 /// 分隔符线高度 31 /// </summary> 32 string lineHeight = "1"; 33 #endregion 34 #region 属性 35 /// <summary> 36 /// 单元格边框颜色 37 /// </summary> 38 public string SplitLineColor 39 { 40 get { Silverlight 中的十进制转换器无法正确处理丢失焦点优化 C# 代码片段、ObservableCollection 和 AddRange