ASP.NET 2.0 使用資料表動態產生TreeView的樹狀結構

摘要:ASP.NET 2.0 使用資料表動態產生TreeView的樹狀結構

前言:

VS.NET2005已經將TreeView放入基本的元件,不過他的資料來源限定為XML檔案或者是Site Map,不過如果我們希望不同的使用者,依照不同的權限來瀏覽不同的網頁時,總不能每個使用者都訂立一個XML檔案來管理,於是小喵就開始尋找如何結合資料表的方式。

此外,當使用者進入系統後,如果每次瀏覽網頁都需要從資料庫撈取一次資料,並且組合一次Tree,小喵覺得似乎有點浪費資源,因此也順便透過Session機制,判斷如果沒有建立過Tree的話,就從資料庫撈資料建立TreeView,當在次瀏覽相關網頁時,如果判斷曾經建立過TreeView,就直接從Session中取回TreeView的結構並且直接顯示,這樣只需再配合一個小小的判斷最後變更權限的時間,來處理Session的存在與否,就能夠減少系統的資源浪費(重複建立撈取相同的TreeView結構)

樹狀結構的資料表設計:

要設計樹狀結構,希望能夠設計出無限層(無限深度)、無限項目的數,小喵的資料表欄位設計如下:

r_TreeView001

說明:

  • NoteId:節點代號,自動編號
  • ParnetId:父層結點代號
  • sText:節點Text
  • sValue:節點Value
  • sURL:超鏈結網址
  • sTarget:超鏈結Target
  • Chger:資料修改者
  • ChgTime:資料修改時間

r_TreeView002

ASP.NET前置作業:

接著開啟一個aspx檔案,並且再畫面上安排一個PlaceHolder控制項,然後在空白地方點兩下,開始撰寫PageOnLoad事件的相關程式

Imports

由於會存取資料庫,所以先將資料庫相關的命名空間Imports進來


Imports System.Data 
Imports System.Data.SqlClient 

編輯Page_Load事件

我們希望在Page_Load的時候,檢查一下是否曾經建立過TreeView,如果有,直接從Session取得TreeView,如果沒有→建立TreeView。

接著就是設定TreeView的ImageSet後,放入PlaceHolder中,相關程式碼如下:


Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    '*****取得Tree物件*****
    '利用Session 當Tree已經建立過,不重新建立,直接從Session中取得,加快速度
    If Session("Tree1") Is Nothing Then
        'Tree不曾建立過→呼叫建立TreeView程序
        Call InitTree() '初始化Tree
        Call BuildTree()    '建立Tree內容
    End If
    '宣告Tree物件
    Dim Tree1 As TreeView
    '從Session中取得Tree物件
    Tree1 = Session("Tree1")

    '設定Tree的ImageSet
    Tree1.ImageSet = TreeViewImageSet.XPFileExplorer
    '置放於PlaceHolder
    Me.PlaceHolder1.Controls.Add(Tree1)
End Sub

初始化TreeView:

在Page_Load中有呼叫初始化TreeView的Sub,接著就來看看初始化TreeView中做了哪些事情。由於一開始還沒有TreeView物件,所以先宣告並實體化TreeView,並且設定【根目錄】節點的相關內容,並指定他回首頁的超鏈結,這部份是靜態的,跟資料庫無關。最後把該Tree放入Session中。


Sub InitTree()
    '********初始化Tree********

    '定義TreeView物件並實體化
    Dim Tree1 As New TreeView
    '定義一個TreeNode並實體化
    Dim tmpNote As New TreeNode
    '設定【根目錄】相關屬性內容
    tmpNote.Text = "首頁"
    tmpNote.Value = "0"
    tmpNote.NavigateUrl = "PtestTreeView3.aspx"
    tmpNote.Target = "_Top"

    'Tree建立該Node
    Tree1.Nodes.Add(tmpNote)

    '將Tree存放入Session中
    Session("Tree1") = Tree1

End Sub

建立樹狀結構程序:

在InitTree程序後,接著是要建立樹狀結構的程序。首先會檢查一下資料是否曾經取得過,如果沒有的話,呼叫取得資料的程序GetDataTable()。接著取得根目錄的節點,然後呼叫新增子節點的Function AddNodes並且傳入【根目錄】節點與根目錄的代號【0】

相關的程式如下:


Sub BuildTree()
    '********建立樹狀結構********

    '宣告TreeView
    Dim Tree1 As TreeView

    '如果Session中沒有Tree,初始化Tree
    If Session("Tree1") Is Nothing Then
        Call InitTree()
    End If
    Tree1 = Session("Tree1")

    '取得根目錄節點
    Dim RootNode As TreeNode
    RootNode = Tree1.Nodes(0)
    Dim rc As String

    '呼叫建立子節點的函數
    rc = AddNodes(RootNode, 0)
    Session("Tree1") = Tree1

End Sub

 

 

 

 

取得資料的程序:

接著是取得資料,並且把DataTable放入Session的相關程式內容如下:

 


Sub GetDataTable()
    '取得DataTable

    '宣告相關變數
    Dim ConnStr As String
    Dim Conn As SqlConnection
    Dim Da As SqlDataAdapter
    Dim Ds As DataSet
    Dim dt As DataTable
    Dim SqlTxt As String

    Try
        '設定連接字串,請修改符合您的資料來源的ConnectionString
        ConnStr = "Data Source=Local\SQLEXPRESS;Persist Security Info=True;User ID=sa;Password=xxxxxxxxxxx;Initial Catalog=DTest"
        '建立Connection
        Conn = New SqlConnection(ConnStr)
        Conn.Open()

        '設定資料來源T-SQL
        SqlTxt = "SELECT * FROM TTestTree"    '請修改您的資料表名稱
        '實體化DataAdapter並且取得資料
        Da = New SqlDataAdapter(SqlTxt, Conn)
        '實體化DataSet
        Ds = New DataSet
        '資料填入DataSet
        Da.Fill(Ds)
        '設定DataTable
        dt = New DataTable
        dt = Ds.Tables(0)
        '將DataTable放入Session中
        Session("Dt") = dt
        '關閉連線
        Conn.Close()

    Catch ex As Exception
        Me.lblMessage.Text = ex.Message
    Finally

        '資源回收
        Ds = Nothing
        Da = Nothing
        Conn = Nothing

    End Try

End Sub

遞回建立子節點函數(AddNodes)

此函數使用遞迴的方式,依照傳入的節點與節點代號,將傳入的節點以下的子節點取出並且建立節點,相關程式內容如下:


Function AddNodes(ByRef tNode As TreeNode, ByVal PId As Integer) As String
    '******** 遞迴增加樹結構節點 ********
    Try
        '如果Session中沒有DataTable→取得DataTable
        If Session("dt") Is Nothing Then
            Call GetDataTable()
        End If
        '定義DataTable
        Dim Dt As DataTable
        '從Session中取得DataTable
        Dt = Session("Dt")

        '定義DataRow承接DataTable篩選的結果
        Dim rows() As DataRow
        '定義篩選的條件
        Dim filterExpr As String
        filterExpr = "ParentId = " & PId
        '資料篩選並把結果傳入Rows
        rows = Dt.Select(filterExpr)

        '如果篩選結果有資料
        If rows.GetUpperBound(0) >= 0 Then


            Dim row As DataRow
            Dim tmpNodeId As Long
            Dim tmpsText As String
            Dim tmpsValue As String
            Dim tmpsUrl As String
            Dim tmpsTarget As String
            Dim NewNode As TreeNode
            Dim rc As String

            '逐筆取出篩選後資料
            For Each row In rows
                '放入相關變數中
                tmpNodeId = row(0)
                tmpsText = row(2)
                tmpsValue = row(3)
                tmpsUrl = row(4)
                tmpsTarget = row(5)

                '實體化新節點
                NewNode = New TreeNode
                '設定節點各屬性
                NewNode.Text = tmpsText
                NewNode.Value = tmpsValue
                NewNode.NavigateUrl = tmpsUrl
                NewNode.Target = tmpsTarget
                '將節點加入Tree中
                tNode.ChildNodes.Add(NewNode)

                '呼叫遞回取得子節點
                rc = AddNodes(NewNode, tmpNodeId)

            Next
        End If
        '傳回成功訊息
        AddNodes = "Success"

    Catch ex As Exception
        Me.lblMessage.Text = ex.Message
        AddNodes = "False"

    End Try
End Function

結語:

以上的示範是把樹狀結構使用資料表的方式存放,並且動態的反應到TreeView中,沒有包含權限控管的部份,如果需要權限控管,可以建立相關權限控管的資料表再與樹狀結構的內容Join。而為了避免每次都要讀取資料庫、建立樹狀結構等相關程式重複執行,透過Session的方式記錄了第一次建立後的結果。並且使用ADO.NET的特色,將撈回來的所有資料先存放到DataTable中,然後之後的資料篩選都是透過離線的DataTable來處理。各位實際在使用的時候可以搭配MasterPage來實做。

 


2008/03/05補充:

後來小喵並沒有使用Session來存放TreeView或者DataTable,也沒有把TreeView放在MasterPage,原因是存放在Session會造成Server記憶體的負擔,而放在MasterPage則是每次瀏覽都要從資料庫撈一次並且遞迴一次,最後小喵還是選擇以往的方式:切割Frame,讓TreeView放在Frame裡面,雖然美觀讓比較沒那麼好,不過在校能與Server的資源使用上卻會有正向的幫忙。提供小喵的經驗給大家參考


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6) 
topcat
Blog:http://www.dotblogs.com.tw/topcat