[ASP.NET]TreeView使用拖拉放的方式更改樹的結構

緣起

剛好在MSDN論壇中看到有人問了這麼個問題,還蠻有趣的,因此小喵就動手嘗試寫看看。這裡面用到了【TreeView結合資料庫】與【client端呼叫Server端事件的技巧】,另外在【TreeNode】沒有Attributes來設定Client端事件時,加入Client端事件的技巧。

背景知識

1.TreeView如何結合資料庫,這部分詳細的解說請參考這一篇

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

2.Client端Script呼叫Server端事件的技巧

如何透過JavaScript來觸發LinkButton的PostBack,呼叫後端的程式

畫面

首先當然在畫面中放個TreeView,另外也放了兩個TextBox用來紀錄要拖拉的NodeId與新的ParentId,另外還需要一個LinkButton,讓Client端的Script可以借用他的Server端事件,透過此事件來維護資料庫。使用TextBox是為了方便除錯、觀察,正式的時候,可以用Hidden物件來取代

我們來看一下畫面的內容

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="JS/jquery.js" type="text/javascript"></script>
    <script type="text/javascript">
        
    </script>
</head>
<body οnselect="document.selection.empty()">
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="lblMsg" runat="server" Text=""></asp:Label>
        <asp:TreeView ID="TreeView1" runat="server" ImageSet="XPFileExplorer" 
            NodeIndent="15">
            <ParentNodeStyle Font-Bold="False" />
            <HoverNodeStyle Font-Underline="True" ForeColor="#6666AA" />
            <SelectedNodeStyle BackColor="#B5B5B5" Font-Underline="False" 
                HorizontalPadding="0px" VerticalPadding="0px" />
            <NodeStyle Font-Names="Tahoma" Font-Size="8pt" ForeColor="Black" 
                HorizontalPadding="2px" NodeSpacing="0px" VerticalPadding="2px" />
        </asp:TreeView>
        <asp:TextBox ID="txtNodeId" runat="server"></asp:TextBox>
        <asp:TextBox ID="txtParentId" runat="server"></asp:TextBox>
        <asp:LinkButton ID="lbChg" runat="server">變更</asp:LinkButton>
        <br />
    </div>
    </form>
</body>
</html>

Server端程式

接著要寫Server端程式,首先當然要先準備資料庫存取的NameSpace

Imports System.Data
Imports System.Data.SqlClient

接著,先宣告一個全域變數用來紀錄Tree的DataTable

Dim Dt As DataTable

然後寫一下TreeView的初始化設定Init

Sub InitTree(ByVal myTreeView As TreeView)
    '********初始化Tree********

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

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

End Sub

接著準備讀取TreeView資料的Sub

Function GetDataTable() As DataTable
    '取得DataTable

    '宣告相關變數
    Dim ConnStr As String
    Dim Da As SqlDataAdapter
    Dim Dt As New DataTable
    Dim SqlTxt As String

    Try
        '設定連接字串,請修改符合您的資料來源的ConnectionString
        ConnStr = ConfigurationManager.ConnectionStrings("MyTestConnStr").ConnectionString
        '建立Connection
        Using Conn = New SqlConnection(ConnStr)

            '設定資料來源T-SQL
            SqlTxt = "SELECT * FROM tTree"    '請修改您的資料表名稱
            '實體化DataAdapter並且取得資料
            Da = New SqlDataAdapter(SqlTxt, Conn)
            '資料填入DataSet
            Da.Fill(Dt)

        End Using

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

    End Try
    Return Dt
End Function

再準備好遞迴建立節點的Function

Function AddNodes(ByRef tNode As TreeNode, ByVal PId As Integer) As String
    '******** 遞迴增加樹結構節點 ********
    Try

        '定義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
                '設定節點各屬性

                '加入Client端Click動作
                '**由於TreeNode無法透過Attributes增加Client端事件,所以在這邊用個小技巧
                '**在Text裡面將本來的文字用個Span包起來,將MouseDown,MouseUp事件寫在裡面
                NewNode.Text = "<span οnmοusedοwn='NodeDown(" & tmpNodeId & ")' οnmοuseup='NodeUp(" & tmpNodeId & ")'>" & tmpsText & "</span>"
                NewNode.Value = tmpNodeId
                '指定選擇的動作
                NewNode.SelectAction = TreeNodeSelectAction.None

                '不給超連結與Target
                'NewNode.NavigateUrl = tmpsUrl
                'NewNode.Target = tmpsTarget

                '將節點加入Tree中
                tNode.ChildNodes.Add(NewNode)

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

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

    Catch ex As Exception
        AddNodes = "False"

    End Try
End Function

再來,運用上面的,撰寫建立樹的Sub

Sub BuildTree(ByVal myTreeView As TreeView)
    '********建立樹狀結構********

    '宣告TreeView
    Dim Tree1 As TreeView = myTreeView

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

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

End Sub

以上這些都好了,就可以在PageLoad的時候,讓樹建立起來

順便把要用的ClientScript準備好,在PageLoad事件中產生

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dt = GetDataTable()
    InitTree(Me.TreeView1)
    BuildTree(Me.TreeView1)

    '撰寫Client端事件,節點的MouseDown,MouseUp
    Dim Script As String = ""
    Script += " <script type='text/javascript'>" + vbCrLf
    Script += "     window.document.select=false; " + vbCrLf
    Script += "  " + vbCrLf
    Script += "  " + vbCrLf
    Script += "  " + vbCrLf
    Script += " function NodeDown(NodeId){ " + vbCrLf
    Script += "     $('#" & Me.txtNodeId.ClientID & "').val(NodeId); " + vbCrLf
    Script += " } " + vbCrLf
    Script += " function NodeUp(NodeId){ " + vbCrLf
    Script += "     $('#" & Me.txtParentId.ClientID & "').val(NodeId); " + vbCrLf
    Script += "     var nid=$('#" & Me.txtNodeId.ClientID & "').val(); " + vbCrLf
    Script += "     var pid=NodeId; " + vbCrLf
    Script += "     if(nid!=pid){ " + vbCrLf
    Script += "         if(window.confirm('您確定要將節點(' + nid + ')搬到節點(' + pid + ')底下嗎??')) " + vbCrLf
    Script += "         { " + vbCrLf
    Script += "             //alert('yes' + pid); " + vbCrLf
    '借用LinkButton的PostBack來運作
    Script += "             __doPostBack('" & Me.lbChg.ClientID & "',''); " + vbCrLf
    Script += "         } " + vbCrLf
    Script += "     } " + vbCrLf
    Script += "      " + vbCrLf
    Script += " } " + vbCrLf
    Script += " </script> " + vbCrLf
    Script += "  "
    Script += "  "

    Page.ClientScript.RegisterClientScriptBlock(Page.GetType, "myScript", Script)

End Sub

到了這邊,Tree就能夠順利的長出來了

再來,開始撰寫變更ParentId的程式碼

維護後,因為架構已經變更,因此要把樹清掉,再重新用新的架構長一次

Private Sub MoveNode(ByVal NodeId As Integer, ByVal ParentId As Integer)
     '自己不能是自己底下,不能搬根目錄
     If NodeId <> ParentId And NodeId <> 1 Then
         Using Conn As New SqlConnection(ConfigurationManager.ConnectionStrings("MyTestConnStr").ConnectionString)
             Dim SqlTxt As String = ""
             '設定改ParentId的SQL語法
             SqlTxt += " UPDATE tTree "
             SqlTxt += " SET ParentId = @ParentId "
             SqlTxt += " WHERE NodeId = @NodeId "
             SqlTxt += "  "

             Using Cmmd As New SqlCommand(SqlTxt, Conn)
                 Cmmd.Parameters.AddWithValue("@ParentId", ParentId)
                 Cmmd.Parameters.AddWithValue("@NodeId", NodeId)
                 Conn.Open()
                 Cmmd.ExecuteNonQuery()

                 '更改後,清除TreeView節點,並重新建立樹結構
                 Me.TreeView1.Nodes.Clear()
                 Dt = GetDataTable()
                 InitTree(Me.TreeView1)
                 BuildTree(Me.TreeView1)
                 '全部展開
                 Me.TreeView1.ExpandAll()
             End Using
         End Using
     End If
 End Sub

接著就是呼叫Server端的事件來呼叫MoveNode

Protected Sub lbChg_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbChg.Click
    Me.lblMsg.Text = Me.txtNodeId.Text & "搬到" & Me.txtParentId.Text & "底下"

    If Me.txtNodeId.Text <> "" And Me.txtParentId.Text <> "" Then
        '如果節點代號、父節點代號有,才運作
        Dim NodeId As Integer = CType(Me.txtNodeId.Text, Integer)
        Dim ParentId As Integer = CType(Me.txtParentId.Text, Integer)
        '呼叫般移節點
        MoveNode(NodeId, ParentId)

    Else
        Me.lblMsg.Text = "必須要有NodeId與ParentId"
    End If

End Sub

執行結果

到這邊已經完成了我們的範例。

執行結果如以下:

 

^_^


2009/8/17補充

話說,要拖拉,還是把拖拉的節點名稱顯示在滑鼠游標旁邊比較有Fu…所以小喵再次修改了一下,看一下運作後的效果先!!

改的地方並不多,首先在畫面上多幾個物件來紀錄,分別是

txtNodeText:紀錄節點的內容

Hidden1:紀錄拖拉的狀態

spanNode:用以顯示在滑鼠旁邊的東西

view plain copy to clipboard print
  1. <asp:TextBox ID="txtNodeText" runat="server"></asp:TextBox> 
  2. <span id="spanNode" style=""></span> 
  3. <input id="Hidden1" type="text" value="0" /> 
<asp:TextBox ID="txtNodeText" runat="server"></asp:TextBox>
<span id="spanNode" style=""></span>
<input id="Hidden1" type="text" value="0" />

接著,修改一下檢點【MouseDown】與【MouseUp】事件中,多紀錄這些內容,寫在CodeFile的PageLoad裡面

view plain copy to clipboard print
  1. '撰寫Client端事件,節點的MouseDown,MouseUp  
  2. Dim Script As String = "" 
  3. Script += " <script type='text/javascript'>" + vbCrLf  
  4. Script += "     window.document.select=false; " + vbCrLf  
  5. Script += "  " + vbCrLf  
  6. Script += " function NodeDown(NodeId,NodeText){ " + vbCrLf  
  7. Script += "     $('#" & Me.txtNodeId.ClientID & "').val(NodeId); " + vbCrLf  
  8. Script += "     $('#Hidden1').val(1); " + vbCrLf  
  9. Script += "     $('#" & Me.txtNodeText.ClientID & "').val(NodeText); " + vbCrLf  
  10. Script += "     $('#spanNode').html(NodeText); " + vbCrLf  
  11. Script += " } " + vbCrLf  
  12. Script += " function NodeUp(NodeId){ " + vbCrLf  
  13. Script += "     $('#Hidden1').val(0); " + vbCrLf  
  14. Script += "     alert('xx'); " + vbCrLf  
  15. Script += "     $('#" & Me.txtParentId.ClientID & "').val(NodeId); " + vbCrLf  
  16. Script += "     var nid=$('#" & Me.txtNodeId.ClientID & "').val(); " + vbCrLf  
  17. Script += "     var pid=NodeId; " + vbCrLf  
  18. Script += "     if(nid!=pid){ " + vbCrLf  
  19. Script += "         if(window.confirm('您確定要將節點(' + nid + ')搬到節點(' + pid + ')底下嗎??')) " + vbCrLf  
  20. Script += "         { " + vbCrLf  
  21. Script += "             //alert('yes' + pid); " + vbCrLf  
  22. '借用LinkButton的PostBack來運作  
  23. Script += "             __doPostBack('" & Me.lbChg.ClientID & "',''); " + vbCrLf  
  24. Script += "         } " + vbCrLf  
  25. Script += "     } " + vbCrLf  
  26. Script += "      " + vbCrLf  
  27. Script += " } " + vbCrLf  
  28. Script += " </script> " + vbCrLf 
'撰寫Client端事件,節點的MouseDown,MouseUp
Dim Script As String = ""
Script += " <script type='text/javascript'>" + vbCrLf
Script += "     window.document.select=false; " + vbCrLf
Script += "  " + vbCrLf
Script += " function NodeDown(NodeId,NodeText){ " + vbCrLf
Script += "     $('#" & Me.txtNodeId.ClientID & "').val(NodeId); " + vbCrLf
Script += "     $('#Hidden1').val(1); " + vbCrLf
Script += "     $('#" & Me.txtNodeText.ClientID & "').val(NodeText); " + vbCrLf
Script += "     $('#spanNode').html(NodeText); " + vbCrLf
Script += " } " + vbCrLf
Script += " function NodeUp(NodeId){ " + vbCrLf
Script += "     $('#Hidden1').val(0); " + vbCrLf
Script += "     alert('xx'); " + vbCrLf
Script += "     $('#" & Me.txtParentId.ClientID & "').val(NodeId); " + vbCrLf
Script += "     var nid=$('#" & Me.txtNodeId.ClientID & "').val(); " + vbCrLf
Script += "     var pid=NodeId; " + vbCrLf
Script += "     if(nid!=pid){ " + vbCrLf
Script += "         if(window.confirm('您確定要將節點(' + nid + ')搬到節點(' + pid + ')底下嗎??')) " + vbCrLf
Script += "         { " + vbCrLf
Script += "             //alert('yes' + pid); " + vbCrLf
'借用LinkButton的PostBack來運作
Script += "             __doPostBack('" & Me.lbChg.ClientID & "',''); " + vbCrLf
Script += "         } " + vbCrLf
Script += "     } " + vbCrLf
Script += "      " + vbCrLf
Script += " } " + vbCrLf
Script += " </script> " + vbCrLf

另外就是,當進行拖拉的時候(MouseMove),顯示節點文字並跟隨滑鼠游標,這部分寫在aspx中的<Script>裡面囉

view plain copy to clipboard print
  1. <script type="text/javascript">  
  2.     $(document).ready(function() {  
  3.         $(document).mousemove(function(e) {  
  4.             //檢查是否在拖拉狀態  
  5.             if ($('#Hidden1').val() == 1) {  
  6.                 //拖拉中,設定顯示位置  
  7.                 var sp = $('#spanNode');  
  8.                 sp.css({position:'absolute',left:e.clientX, top:e.clientY});  
  9.             }  
  10.             else {  
  11.                 $('#spanNode').html('');  
  12.             }  
  13.         });  
  14.     })  
  15. </script> 
<script type="text/javascript">
    $(document).ready(function() {
        $(document).mousemove(function(e) {
            //檢查是否在拖拉狀態
            if ($('#Hidden1').val() == 1) {
                //拖拉中,設定顯示位置
                var sp = $('#spanNode');
                sp.css({position:'absolute',left:e.clientX, top:e.clientY});
            }
            else {
                $('#spanNode').html('');
            }
        });
    })
</script>

而拖拉的範圍是整個Document,所以寫在Document的mousemove事件中

詳細完整的程式碼請點選下面下載

 

原始碼下載2

转载于:https://www.cnblogs.com/topcat/archive/2009/08/06/1540303.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值