动态创建和填充 Treeviews






4.67/5 (9投票s)
2006 年 3 月 31 日
2分钟阅读

110518

3000
关于数据库驱动的动态多 Treeviews 的文章
引言
在我最近的一个项目中,需求的一部分是生成 KPI 记分卡。KPI 记分卡是一个以树状结构显示 KPI 的图表。所有的 KPI 都被分类,每个类别代表一棵树。树的层次结构在数据库中定义。这基本上要求根据数据库中的详细信息动态生成 Treeview。
我一直在尝试寻找关于 Web 上 Treeview 的资源。我找不到这样的确切示例。我可以找到在设计时添加到 Web 表单的 Treeview 的文章,以及将控件动态添加到 Web 表单的文章,但没有例子说明动态 Treeview 控件。因此,我考虑上传这篇文章,这篇文章说明了如何动态创建和数据绑定 Treeview。
我非常确定这没有什么新的(不为人知的)。本文只是在 Web 上找到的两类文章(Treeview 和动态添加控件)的结合,这对于一些可以根据自己的使用情况进行定制的人来说可能是一个现成的解决方案。
对于这篇文章,我使用了 VS 2003,SQL Server 数据库。这是一个示例项目,其中我使用了 Microsoft Treeview 控件,而在我的实际项目中,我使用了第三方 treeview 控件,以获得更大的灵活性和更好的美观视图。
数据库准备
这个项目的数据库包含两个表 1. SC_Master 2. SC_Detail
表结构和数据如下。(用于生成表的脚本包含在源代码的 Database 文件夹中。)
SC_Master
SC_Detail
项目结构
使用代码
这个项目的核心是一个用户控件 "Scorecard.ascx",它创建并填充了 treeview。使用用户控件的主页面是 "ScorecardPage.aspx"。首先让我们讨论一下用户控件中的代码。
从数据库检索数据的函数
#Region " Retrieve DataSet "
Public Function Retrieve_DataSet(ByVal sSQL As String) As DataSet
Dim cmdCommand As New OleDbCommand()
Try
Dim daAdapter As New OleDbDataAdapter()
Dim dsDataSet As New DataSet()
'Connection String should be changed suitably.
Dim cnConnection As New OleDbConnection("Provider=SQLOLEDB;" & _
"Password=MyPwd;User ID=MyId;" & _
"Data Source=MyServer;Initial Catalog=SCORECARD;")
cnConnection.Open()
With cmdCommand
.Connection = cnConnection
.CommandType = CommandType.Text
.CommandText = sSQL
End With
daAdapter.SelectCommand = cmdCommand
dsDataSet.EnforceConstraints = False
daAdapter.Fill(dsDataSet)
dsDataSet.EnforceConstraints = True
Return dsDataSet.Copy
Catch err As Exception
'Throw err
Response.Write(err.StackTrace)
Finally
cmdCommand.Connection.Close()
End Try
End Function
#End Region
创建和填充 Treeview 的代码
#Region " Generate Treeviews "
Private Sub CreateRootnodes()
Dim dbRow As System.Data.DataRow
Dim ds As New System.Data.DataSet()
Dim strSqlMain As String = "select m.SC_ID_NO as SC_ID_NO, " & _
"m.SC_SHORT_DESC as SC_SHORT_DESC,m.SC_PARENT as SC_PARENT,"
strSqlMain = strSqlMain & " sum(d.SC_ACTUAL) as SC_ACTUAL,"
strSqlMain = strSqlMain & " sum(d.SC_PLAN) as SC_PLAN,"
strSqlMain = strSqlMain & " sum(d.SC_ACTUAL - d.SC_PLAN) as SC_Better"
strSqlMain = strSqlMain & " from SC_Master m, SC_Detail d"
strSqlMain = strSqlMain & _
" where d.SC_ID = m.SC_ID_NO and m.SC_PARENT is NULL"
strSqlMain = strSqlMain & " group by SC_ID_NO,SC_SHORT_DESC,SC_PARENT"
strSqlMain = strSqlMain & " order by SC_ID_NO"
ds = Retrieve_DataSet(strSqlMain)
Dim i As Int32
Dim tbl As New Table()
Dim tblrow As New TableRow()
For Each dbRow In ds.Tables(0).Rows
Dim newTreeview As New TreeView()
Dim tblcel As New TableCell()
newTreeview.ShowLines = True
Dim strSqlSub As String = "select m.SC_ID_NO as SC_ID_NO, " & _
"m.SC_SHORT_DESC as SC_SHORT_DESC,m.SC_PARENT as SC_PARENT,"
strSqlSub = strSqlSub & " sum(d.SC_ACTUAL) as SC_ACTUAL,"
strSqlSub = strSqlSub & " sum(d.SC_PLAN) as SC_PLAN,"
strSqlSub = strSqlSub & " sum(d.SC_ACTUAL - d.SC_PLAN) as SC_Better"
strSqlSub = strSqlSub & " from SC_Master m, SC_Detail d"
strSqlSub = strSqlSub & " where d.SC_ID = m.SC_ID_NO and (m.SC_PARENT='"
strSqlSub = strSqlSub & dbRow("SC_ID_NO").ToString() & "' or m.SC_ID_NO='"
strSqlSub = strSqlSub & dbRow("SC_ID_NO").ToString() & "')"
strSqlSub = strSqlSub & " group by SC_ID_NO,SC_SHORT_DESC,SC_PARENT"
strSqlSub = strSqlSub & " order by SC_ID_NO"
buildTree(newTreeview, strSqlSub)
tblcel.ID = dbRow("SC_ID_NO").ToString()
tblcel.Controls.Add(newTreeview)
tblcel.VerticalAlign = VerticalAlign.Top
tblrow.Cells.Add(tblcel)
Next dbRow
tbl.Rows.Add(tblrow)
tbl.ID = "TreeTable"
Me.Controls.Add(tbl)
End Sub
Private Sub buildTree(ByRef treeview As TreeView, ByVal sql As String)
Dim dbSubTreeRow As System.Data.DataRow
Dim dsSubtree As New System.Data.DataSet()
dsSubtree = Retrieve_DataSet(sql)
dsSubtree.Relations.Add("NodeRelation", _
dsSubtree.Tables(0).Columns("SC_ID_NO"), _
dsSubtree.Tables(0).Columns("SC_PARENT"))
Dim strNodeText As String
For Each dbSubTreeRow In dsSubtree.Tables(0).Rows
If (dbSubTreeRow.IsNull("SC_PARENT")) Then
Dim newNode As TreeNode
strNodeText = Trim(dbSubTreeRow("SC_SHORT_DESC").ToString())
Dim j As Int32
Dim addstr As String = ""
For j = 1 To 40
addstr = addstr & " "
Next
strNodeText = addstr & "
" & strNodeText & "
" & Format(dbSubTreeRow("SC_Better"), Me.dfDecimal)
newNode = CreateNode(strNodeText, "", True)
'greenBackground,yellowBackground,redBackground
'are strings which contain the style sheet.
If dbSubTreeRow("SC_Better") > 0 Then
newNode.SelectedStyle = _
CssCollection.FromString(greenBackground)
newNode.DefaultStyle = _
CssCollection.FromString(greenBackground)
newNode.HoverStyle = _
CssCollection.FromString(greenBackground)
ElseIf dbSubTreeRow("SC_Better") = 0 Then
newNode.SelectedStyle = CssCollection.FromString(yellowBackground)
newNode.DefaultStyle = CssCollection.FromString(yellowBackground)
newNode.HoverStyle = CssCollection.FromString(yellowBackground)
Else
newNode.SelectedStyle = CssCollection.FromString(redBackground)
newNode.DefaultStyle = CssCollection.FromString(redBackground)
newNode.HoverStyle = CssCollection.FromString(redBackground)
End If
newNode.Expanded = True
newNode.Expandable = ExpandableValue.Always
treeview.Nodes.Add(newNode)
PopulateSubTree(dbSubTreeRow, newNode)
End If
Next dbSubTreeRow
End Sub
Private Sub PopulateSubTree _
(ByVal dbRow As System.Data.DataRow, _
ByVal node As TreeNode)
Dim childRow As System.Data.DataRow
Dim strNodeText As String
Dim j As Int32
Dim addstr As String = ""
For j = 1 To 40
addstr = addstr & " "
Next
For Each childRow In dbRow.GetChildRows("NodeRelation")
strNodeText = Trim(childRow("SC_SHORT_DESC").ToString())
strNodeText = addstr & "
" & strNodeText & "
" & Format(childRow("SC_Better"), Me.dfDecimal)
Dim childNode As TreeNode = _
CreateNode(strNodeText, "", True)
If childRow("SC_Better") > 0 Then
childNode.SelectedStyle = CssCollection.FromString(greenBackground)
childNode.DefaultStyle = CssCollection.FromString(greenBackground)
childNode.HoverStyle = CssCollection.FromString(greenBackground)
ElseIf childRow("SC_Better") = 0 Then
childNode.SelectedStyle = CssCollection.FromString(yellowBackground)
childNode.DefaultStyle = CssCollection.FromString(yellowBackground)
childNode.HoverStyle = CssCollection.FromString(yellowBackground)
Else
childNode.SelectedStyle = CssCollection.FromString(redBackground)
childNode.DefaultStyle = CssCollection.FromString(redBackground)
childNode.HoverStyle = CssCollection.FromString(redBackground)
End If
node.Expanded = True
node.Expandable = ExpandableValue.Always
node.Nodes.Add(childNode)
PopulateSubTree(childRow, childNode)
Next childRow
End Sub
Private Function CreateNode _
(ByVal text As String, ByVal _
imageurl As String, ByVal expanded As Boolean) _
As TreeNode
Dim node As New TreeNode()
node.Text = text
node.ImageUrl = imageurl
node.Expanded = expanded
Return node
End Function
#End Region
初始化用户控件显示的初始化代码。
Public Sub InitDisplay()
Try
CreateRootnodes()
Catch err As Exception
Response.Write(err.Message)
End Try
End Sub
在 "ScorecardPage.aspx" 上显示用户控件的代码
#Region " Show Controls "
Public Sub ShowControls()
Dim ucScoreCard As Scorecard = _
Page.LoadControl("..\Components\Scorecard.ascx")
ucScoreCard.ID = "ucScoreCard"
Me.PlaceHolder1.Controls.Clear()
PlaceHolder1.Controls.Add(ucScoreCard)
ucScoreCard.InitDisplay()
End Sub
#End Region
在 "ScorecardPage.aspx" 的页面加载事件中调用 "ShowControls" 方法。
关注点
有很多事情可以用 treeview 属性来完成,但我在本文中没有提及。我使用了样式表来获取所需的背景,这些背景突出显示了元素的值(负数、正数和零)。
注释
请花时间为本文投票和/或评论它。
历史
2006 年 3 月 31 日 - 初始版本