65.9K
CodeProject 正在变化。 阅读更多。
Home

从表到 TreeView…显示层次结构

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (7投票s)

2009 年 4 月 1 日

CPOL

2分钟阅读

viewsIcon

64504

谁还记得对象数据库? 曾经它们有望统治编程世界。 但就像许多被过度炒作的技术(Lisp、AI、ADA、虚拟现实)一样,它们注定要占据市场的一小部分利基领域。 关系数据库仍然是王者。 为什么? 因为关系数据库

谁还记得对象数据库? 曾经它们有望统治编程世界。 但就像许多被过度炒作的技术(Lisp、AI、ADA、虚拟现实)一样,它们注定要占据市场的一小部分利基领域。

关系数据库仍然是王者。 为什么? 因为关系数据库易于理解,而且效果很好……非常好。

尽管如此,很多时候层次数据存储在关系数据库中。 一个常见的例子是组织结构图。 这通常存储在一个 Employee 表中。 每个表行代表一个员工,包含一个 ID 字段和一个 ParentID(上司)字段。

这段代码展示了如何从层次表转换为树形视图。 这里没有什么复杂的,但需要一些技巧才能使其工作。

第一个技巧按 ParentID 排序记录。 我们不能将节点插入到树中,直到其父节点在树中。 这意味着需要一种特殊情况,即首先插入树的根节点,因为它没有父节点。

这里是示例数据

// Create the DataTable and columns
DataTable ItemTable = new DataTable("MyTable");
ItemTable.Columns.Add("ID"      , typeof(int   ));
ItemTable.Columns.Add("ParentID", typeof(int   ));
ItemTable.Columns.Add("Name"    , typeof(String));

// add some test data
ItemTable.Rows.Add(new object[] { 0,-1, "Bill Gates"    });
ItemTable.Rows.Add(new object[] { 1, 0, "Steve Ballmer" });
ItemTable.Rows.Add(new object[] { 3, 1, "Mary Smith"    });
ItemTable.Rows.Add(new object[] { 2, 0, "Paul Allen"    });
ItemTable.Rows.Add(new object[] { 4, 2, "Ahmed Jones"   });
ItemTable.Rows.Add(new object[] { 5, 2, "Wing Lee"      });

// Use the Select method to sort the rows by ParentID
DataRow[] SortedRows;
SortedRows = ItemTable.Select("", "ParentID");

第二个技巧是使用 XmlDocument。 最初,我尝试直接连接到树形视图,而无需中间数据对象。 但树形视图控件没有功能可以根据节点 ID 找到任意节点。 编写递归查找函数似乎需要很多工作,因此我们利用 XmlDocument 的 XPath 搜索功能来查找任意父节点。

// create an XmlDocument (with an XML declaration)
XmlDocument XDoc = new XmlDocument();
XmlDeclaration XDec = XDoc.CreateXmlDeclaration("1.0", null, null);
XDoc.AppendChild(XDec);

// iterate through the sorted data
// and build the XML document
foreach (DataRow Row in SortedRows)
{
    // create an element node to insert
    // note: Element names may not have spaces so use ID
    // note: Element names may not start with a digit so add underscore
    XmlElement NewNode = XDoc.CreateElement("_" + Row["ID"].ToString());
    NewNode.SetAttribute("ID"      , Row["ID"].ToString());
    NewNode.SetAttribute("ParentID", Row["ParentID"].ToString());
    NewNode.SetAttribute("FullName", Row["Name"].ToString());

    // special case for top level node
    if ((int)Row["ParentID"] == -1)
        XDoc.AppendChild(NewNode);  // root node
    else
    {
        // use XPath to find the parent node in the tree
        String SearchString;
        SearchString = String.Format("//*[@ID=\"{0}\"] ", Row["ParentID"].ToString());
        XmlNode Parent = XDoc.SelectSingleNode(SearchString);

        if (Parent != null)
            Parent.AppendChild(NewNode);
        else
            ; // Handle Error: Employee with no boss
    }
}

第三个技巧涉及文档中的一个错误。 树形视图(或菜单)无法绑定到 XmlDocument。 这样做会产生此错误:HierarchicalDataBoundControl only accepts data sources that implement IHierarchicalDataSource or IHierarchicalEnumerable。 解决方法是动态创建一个 XmlDataSource 控件,并将 XML 字符串分配给它。

// we cannot bind the TreeView directly to an XmlDocument
// so we must create an XmlDataSource and assign the XML text
XmlDataSource XDdataSource = new XmlDataSource();
XDdataSource.ID = DateTime.Now.Ticks.ToString();  // unique ID is required
XDdataSource.Data = XDoc.OuterXml;

// we want the full name displayed in the tree so 
// do custom databindings
TreeNodeBinding Binding = new TreeNodeBinding();
Binding.TextField = "FullName";
Binding.ValueField = "ID";
TreeView1.DataBindings.Add(Binding);

// Finally! Hook that bad boy up!       
TreeView1.DataSource = XDdataSource;
TreeView1.DataBind();

完成所有这些工作后,结果如下

希望对您有所帮助,

史蒂夫·韦伦斯。

附言:新年快乐 2008++;

© . All rights reserved.