Avatar billede neoman Novice
21. oktober 2007 - 14:50 Der er 6 kommentarer og
2 løsninger

Flytte treeview nodes interaktivt

Nu har jeg bakset med det længe nok. Jeg skal interaktivt flytte nodes/branches på en træstruktur: vælge en node og dens children, hægte dem af træet et sted og tilføje et andet sted.

Jeg gør det ved at klikke på den node som skal hægtes af, og huske den. Det næste klik  markerer den node hvor den afhægtede  node skal tilføjes. Det virker som vinden blæser, og jeg har stirret mig blind.

Prøv lige selv at se hvad der sker, hvis en node som allerede har children, skal hægtes af.

kode:
Partial Class Deps
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim Departments(10) As String
        Departments(0) = "Dept1"
        Departments(1) = "Dept2"
        Departments(2) = "Dept3"
        Departments(3) = "Dept4"
        Departments(4) = "Dept5"
        Departments(5) = "Dept6"
        Departments(6) = "Dept7"
        Departments(7) = "Dept8"
        Departments(8) = "Dept9"
        Departments(9) = "Dept10"

        Dim mytree As TreeView

        mytree = TreeView1
        If Not Page.IsPostBack Then
            Dim root As New TreeNode("root")
            mytree.Nodes.Add(root)
            For i As Integer = 0 To 10
                Dim myNode As New TreeNode
                myNode.Text = Departments(i)
                root.ChildNodes.Add(myNode)
                Response.Write(mytree.Nodes.IndexOf(myNode))
            Next
        End If
    End Sub


    Protected Sub TreeView1_SelectedNodeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TreeView1.SelectedNodeChanged
        Dim nodeToMove As TreeNode
        Dim marked As TreeNode
        Dim myIndex As Integer = 0
        If IsNothing(Session("nodeToMove")) Then
            nodeToMove = TreeView1.SelectedNode
            nodeToMove.Parent.ChildNodes.Remove(nodeToMove)
            ' TreeView1.Nodes.Remove(nodeToMove)
            Session("nodeToMove") = nodeToMove
        Else
            nodeToMove = CType(Session("nodeToMove"), TreeNode)
            marked = TreeView1.SelectedNode
            marked.ChildNodes.Add(nodeToMove)
            Session("nodeToMove") = Nothing
        End If
    End Sub
End Class

aspx:
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Deps.aspx.vb" Inherits="Deps" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
                <br />
            <br />
              <asp:TreeView ID="TreeView1" runat="server" ShowExpandCollapse="False" >
            </asp:TreeView>     
            <br />
            <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
</body>
</html>

Hvem har en god idé ?




AFK for quite a while.
Avatar billede dr_chaos Nybegynder
21. oktober 2007 - 15:18 #1
Jeg har en færdig kontrol lavet i c# som du kan benytte hvis du er interesseret.
Den ligger i en selvstændig dll.
Den fungerer v.ha. javascript og postback.
Avatar billede neoman Novice
21. oktober 2007 - 22:20 #2
Tak for tilbudet Dr.C, skal overveje det - slår ikke til endnu, fordi en dll  ikke løser mit problem med at jeg SKAL forstå hvordan det fungerer, fordi jeg har brug for at løbe op og ned ad træet og vide hvor jeg er, når jeg enten skal danne hierarkiet  på et udtræk fra db'en , eller gemme den (eller ændringer i den) i db'en.


MSDN sucks big time - de glemte lige at nævne, at Treeview.Nodes.IndexOf(myNode) ikke giver noget brugbart hvis noden ikke er en root node, i hvilket tilfælde man skal bruge myNode.Parent.ChildNodes.IndexOf(myNode). De har ligeledes glemt den lille detalje, at Index i det hele taget er en indeksering  for nodes med samme parent, og ikke en "global" index af alle nodes.

Work in progress, stay tuned:)
Avatar billede dr_chaos Nybegynder
21. oktober 2007 - 22:44 #3
ok.
Det er en som jeg har lavet med javascript og nogle hidden fields.
Jeg har ikke fundet andre som har givet et færdigt eksempel på nettet.

Hvis du skal flytte en node skal du makerer den og evt vise at den er blevet valgt og når du så trykker på den nye node finder du de 2 noder med valuepath og treeview.FindNode().
Du kan enten tilføje en node som Child til den nye node eller som parent's child.
Avatar billede neoman Novice
22. oktober 2007 - 16:43 #4
Så har jeg fået det op at køre. Der var lidt problemer med display af de nodes som er blevet flyttet, da de først vises rigtigt i næste postback. Jeg formoder det er fordi de childnodes som ikke selv blev flyttet direkte, men kun fordi parentnode blev flyttet, ikke får opdateret deres viewstate, og derfor ikke viser deres fysiske offset korrekt. Ud fra den teori så har jeg indlagt en  metode som blot remover og adder alle child nodes for den node som blev flyttet, og det løste problemet.

Entusiaster, som ønsker at se hvad den gør, kan blot udkommentere FiddleNode.

Imports System.Collections.Generic
Partial Class Deps
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim Departments(10) As String
        Departments(0) = "Dept1"
        Departments(1) = "Dept2"
        Departments(2) = "Dept3"
        Departments(3) = "Dept4"
        Departments(4) = "Dept5"
        Departments(5) = "Dept6"
        Departments(6) = "Dept7"
        Departments(7) = "Dept8"
        Departments(8) = "Dept9"
        Departments(9) = "Dept10"

        Dim mytree As TreeView

        mytree = TreeView1
        If Not Page.IsPostBack Then
            Dim myroot As New TreeNode("root")
            mytree.Nodes.Add(myroot)
            For i As Integer = 0 To 10
                Dim myNode As New TreeNode
                myNode.Text = Departments(i)
                myroot.ChildNodes.Add(myNode)
                ' myroot = myNode
            Next
        End If
    End Sub


    Protected Sub TreeView1_SelectedNodeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TreeView1.SelectedNodeChanged
        Dim nodeToMove As TreeNode
        Dim myList As List(Of Integer)

        Dim marked As TreeNode
        Dim myIndex As Integer = 0
        If IsNothing(Session("nodeToMove")) Then
            nodeToMove = TreeView1.SelectedNode
            ' TreeView1.Nodes.Remove(nodeToMove)
            myList = GetParents(nodeToMove)
            Session("myList") = myList
            Session("nodeToMove") = nodeToMove
        Else
            'nodeToMove = CType(Session("nodeToMove"), TreeNode)
            myList = CType(Session("myList"), List(Of Integer))
            nodeToMove = GetNode(myList)
            If Not IsNothing(nodeToMove.Parent) Then
                nodeToMove.Parent.ChildNodes.Remove(nodeToMove)
            Else
                TreeView1.Nodes.Remove(nodeToMove)
            End If
            marked = TreeView1.SelectedNode
            marked.ChildNodes.Add(nodeToMove)
            'remove and reattach each childe node, otherwise it's offset is first
            'shown on next postback
            FiddleNode(nodeToMove)

            TreeView1.SelectedNode.Selected = False

            Session("nodeToMove") = Nothing
            Session("myList") = Nothing
        End If
    End Sub


    Sub FiddleNode(ByVal MyNode As TreeNode)
        'removes and readds each node
        Dim myIndex As Integer
        Dim parentNode As TreeNode
        If Not IsNothing(MyNode.Parent) Then
            parentNode = MyNode.Parent
            myIndex = parentNode.ChildNodes.IndexOf(MyNode)
            parentNode.ChildNodes.Remove(MyNode)
            parentNode.ChildNodes.AddAt(myIndex, MyNode)
        End If

        For i As Integer = 0 To MyNode.ChildNodes.Count - 1

            FiddleNode(MyNode.ChildNodes(i))
        Next i
    End Sub

    Function GetParents(ByVal myNode As TreeNode) As List(Of Integer)
        'finds the indices og all parents and saves them in myList
        Dim myList As New List(Of Integer)
        Do While Not IsNothing(myNode.Parent)
            myList.Insert(0, myNode.Parent.ChildNodes.IndexOf(myNode))
            myNode = myNode.Parent
        Loop
        myList.Insert(0, TreeView1.Nodes.IndexOf(myNode))
        Return myList
    End Function

    Function GetNode(ByVal myList As List(Of Integer)) As TreeNode
        'finds a node by indices stored in myList
        Dim count As Integer = myList.Count
        Dim myNode As TreeNode
        For i As Integer = 0 To count - 1
            If i = 0 Then
                myNode = TreeView1.Nodes(myList(i))
            Else
                myNode = myNode.ChildNodes(myList(i))
            End If
        Next
        Return myNode
    End Function

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

    End Sub

End Class


Dr.C - jeg holder fast i ovenstående, fordi der skal ske en hel del andre ting som gør at jeg alligevel smider mit treeview ind i et UpdatePanel, når det hele kører. Men mange tak for tanken. Læg et svar så kan jeg give dig en andel for moralsk støtte:)
Avatar billede dr_chaos Nybegynder
22. oktober 2007 - 19:54 #5
Svar :)
Avatar billede neoman Novice
22. oktober 2007 - 20:06 #6
.
Avatar billede neoman Novice
22. oktober 2007 - 20:07 #7
oops - og prøv lige med en kommentar så, Dr.C!:)
Avatar billede dr_chaos Nybegynder
22. oktober 2007 - 20:09 #8
********* svar:)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester