[我有废话要说]
PA的U。M界面的树也是我封装的,做这个功能的时候,我希望它可以像smart-gwt的treeGrid一样好用。
不过我不会C#,也第一次写ASP控件,还想让他像treeGrid……在这个难度上,我想再加点,把我的树写的通用又好维护,于是我决定好好设计,加入设计模式的思想:)
[正文——封个控件来画树]
需求:
领导说写个读取XML配置,让后封装成树,在界面上展示出来。
我是个画蛇添足的程序员,我想分两步完成,希望这个题目能两天就写完。
第一步:
从XML解析一棵树,放到tree中。并且考虑:如果XML格式变了、如果不从XML取数据库……要让我的代码尽量满足开闭原则。
第二步:
做一个渲染树的控件,将这个树丢到控件中,树就画出来了,可以多列。
开始干活:
我的树的设计
用户通过工厂类得到一个XML工厂。
XMLTreeReader工厂解析XML文件,把XML配置的指定解析自己的ITreeReader返回。(比如扁平或层级的表示树形的XML文件)
ITreeReader一拿到就可以开始干活了,ITreeReader解析xml的节点,把数据封装到树结构ITreeNode中。
这里需要注意的是:ITreeNode表示一个树的树根节点,有节点的属性,还有子节点。因此ITreeReader解析时候,需要创建子节点,也就是ITreeNode对象。而ITreeNode是接口,不能new出来,所以ITreeReader需要知道ITreeNode的实现类,于是我传入ITreeReader一个ITreeNode的实现类,反射来创建对象。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace com.Origin.Base.test.mywork.Tree { public interface ITreeReaderFactory { ITreeReader createTreeReader(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace com.Origin.Base.test.mywork.Tree { public class XMLTreeRreaderFactory:ITreeReaderFactory { private string xmlPath {set;get; } public XMLTreeRreaderFactory(string path) { xmlPath = path; } public ITreeReader createTreeReader() { //解析xmlPath路径下的xml文件,根据XML配置取得解析该XML对应的类,反射回去. //这里把解析XML的一段省略了先,直接写死读到了xml配置的类: string className = "com.Origin.Base.test.mywork.Tree.SimpleTreeReader"; Type type = Type.GetType(className); Console.WriteLine(" 解析XML的类:" + type); ITreeReader reader = (ITreeReader)type.Assembly.CreateInstance(className); return reader; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace com.Origin.Base.test.mywork.Tree { public interface ITreeReader { ITreeNode createTree(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace com.Origin.Base.test.mywork.Tree { public class SimpleTreeReader:ITreeReader { private static string DEFAULT_NODE_CLASS = "com.Origin.Base.test.mywork.Tree.MyTreeNode"; private string treeNodeClassName { set; get; } public ITreeNode createTree() { ITreeNode treeNode = createNode(); //根据XML的结构,解析XML文件,封装到ITreeNode的对象中,返回 //这里不读取XML了,直接用假数据封装下。 treeNode.putAttribute("name"," 用户管理"); treeNode.putAttribute("url"," /userManage.html"); //创建子树 ITreeNode subNode = createNode(); subNode.putAttribute("name", "创建用户"); subNode.putAttribute("url", " /createUser.html"); treeNode.addSubNode(subNode); return treeNode; } private ITreeNode createNode() { if (treeNodeClassName == null) { treeNodeClassName = DEFAULT_NODE_CLASS; } //再次用到反射 Type type = Type.GetType(treeNodeClassName); ITreeNode treeNode = (ITreeNode)type.Assembly.CreateInstance(treeNodeClassName); return treeNode; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace com.Origin.Base.test.mywork.Tree { public abstract class ITreeNode { protected IList<ITreeNode> subNodes { get; set; } //设置当前节点的key-value对 public abstract void putAttribute(object key, object value); //根据key得到对应的值 public abstract object getAttribute(object key); //为当前节增加一个子节点,在它的节点的下一级节点的末尾增加 public abstract void addSubNode(ITreeNode node); public abstract IList<ITreeNode> getSubNodes(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Collections; namespace com.Origin.Base.test.mywork.Tree { public class MyTreeNode : ITreeNode { private Hashtable attributes = new Hashtable(); //设置当前节点的key-value对 public override void putAttribute(object key, object value) { attributes.Add(key,value); } //根据key得到对应的值 public override object getAttribute(object key) { if (attributes.Contains(key)) { return attributes[key]; } else { return null; } } //为当前节增加一个子节点,在它的节点的下一级节点的末尾增加 public override void addSubNode(ITreeNode node) { if (subNodes == null) { subNodes = new List<ITreeNode>(); } subNodes.Add(node); } public override IList<ITreeNode> getSubNodes() { return subNodes; } } }
看看client调用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using com.Origin.Base.test.mywork.Tree; namespace ConsoleApplication1 { class Program { private ITreeReaderFactory factory = new XMLTreeRreaderFactory(@"D:\\menu.xml"); public ITreeNode fetchTreeNode() { ITreeNode root = null; ITreeReader reader = factory.createTreeReader(); root = reader.createTree(); return root; } static void Main(string[] args) { Console.WriteLine("start..."); Program p = new Program(); ITreeNode root = p.fetchTreeNode(); string tab =""; printTree(root, tab); Console.ReadLine(); } public static void printTree(ITreeNode node,string s) { s = " " + s; Console.WriteLine(s + "NAME = " + node.getAttribute("name") + " url = " + node.getAttribute("url")); IList<ITreeNode> subNodes = node.getSubNodes(); if (subNodes == null) { return; } for (int i = 0; i < subNodes.Count; i++) { printTree(subNodes[i],s); } } } }
输出: