我最终创建了两个函数来以更动态和可扩展的方式执行此操作。
public static TreeNodeCollection SqlToTreeNodeHierarchy(this SqlDataReader dataReader, TreeNode parent)
{
// create a parent TreeNode if we don't have one, so we can anchor the new TreeNodes to it
// I think this will work better than a list since we might be given a real parent..
if (parent == null)
{
parent = new TreeNode("topNode");
}
while (dataReader.Read())
{
//at the beginning of each row, reset the parent
var parentNode = parent;
for (var i = 0; i < dataReader.FieldCount; i++)
{
// Adds a new TreeNode as a child of parentNode if it doesn't already exist
// at this level, else it will return the existing TreeNode and save
// it onto parentNode. This way, subsequent TreeNodes will always be a child
// of this one, until a new row begins and the parent TreeNode is reset.
parentNode = AddUniqueNode(dataReader[i].ToString(), parentNode);
}
}
return parent.Nodes;
}
public static TreeNode AddUniqueNode(string text, TreeNode parentNode)
{
// if parentNode is null, create new treeNode and return it
if (parentNode == null)
{
return new TreeNode {Name = text, Text = text};
}
// if parentNode is not null, do a find for child nodes at this level containing the key
// we're after (text and name have the same value) and return the first one it finds
foreach (var childNode in parentNode.Nodes.Find(text, false))
{
return childNode;
}
// Node does not yet exist, so just add a new node to the parentNode and return that
return parentNode.Nodes.Add(text, text);
}
然后我只需要如下调用函数:
using (var sqlConn = new SqlConnection(connectionString))
{
sqlConn.Open();
const string query = "SELECT orderDate, customerName from MAIN";
using (var sqlCommand = new SqlCommand(query, sqlConn))
{
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
var treeNodeCollection = sqlDataReader.SqlToTreeNodeHierarchy(null);
foreach (TreeNode treeNode in treeNodeCollection)
{
nativeTreeView.Nodes.Add(treeNode);
}
}
}
}
通过这种方式,我可以使用任意数量的子节点对其进行扩展,并且它还为我提供了仅在展开时加载子节点的灵活性,方法是执行另一个 SQL 查询并将父节点作为刚刚展开的 TreeNode 传递。