首页 > 解决方案 > Deep copy a CUSTOM treenode

问题描述

I am researching for some days now how to shallow copy and deep copy a custom TreeNode object that was dragged from treeview1 and Dropped to Treeview2. I need both behaviors in my application. I can create the custom TreeNode and have the custom properties populated from SQL Database. The main idea is to have all product options in the Treeview1 and build my product in the Treeview2.

What I can do...

1)Populate Treeview1 from SQL Database

2)Create the CUSTOM TreeNode with my properties

3)DragItem, DragEnter, DragOver and DragDrop my Custom TreeNode

What is my problem?

When I DragDrop the CUSTOM TreeNode from TreeView1 and I Add the TreeNode in the TreeView2 I need to remove the TreeNode from TreeView1 But I Would like to have the CUSTOM TreeNode on Both places TreeView1 and TreeView2.

I did a lot of research but I believe I need some guidance from you colleagues to accomplish my gol. I tried a lot of things also without success...This is the code I have that supposed to do a DeepCopy from my CUSTOM TreeNode. The concept for the DeepCopy function I took from Microsoft documentation regarding CLONE (Shallow and DeepCopy). Here is my code.

Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Public Class Frm_USER_HDAS
    Private Sub Frm_USER_HDAS_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        TreeView1.Nodes.Clear()

        TreeView1.Nodes.Add("Nodes_Collection")
        TreeView1.Nodes(0).Text = "Nodes_Collection"

        Try

            Call DBOpenConnection()

            Dim CurrentTableName As String = "Customers"

            Dim NewNode As HDAS_TreeNode
            Dim DTProperties As New DataTable

            Dim returnProperties As String = DB.SQLQuery("SELECT * FROM [" + CurrentTableName + "]", DTProperties)

            For j As Integer = 0 To DTProperties.Rows.Count - 1

                For k As Integer = 0 To DTProperties.Columns.Count - 1

                    If DTProperties.Columns(k).ColumnName = "Name" Then

                        Dim DT_ItemProperties As New DataTable

                        Dim retorn_DT_ItemProperties As String = DB.SQLQuery("SELECT * 
                                                                              FROM [" + CurrentTableName + "] 
                                                                              WHERE Name = '" + DTProperties.Rows(j).Item(k) + "';",
                                                                              DT_ItemProperties)

                        Dim DTLinks As New DataTable

                        Dim ReturnLinks As String = DB.SQLQuery("SELECT
                                    c.CONSTRAINT_NAME,
                                    cu.TABLE_NAME AS ReferencingTable,
                                    cu.COLUMN_NAME AS ReferencingColumn,
                                    ku.TABLE_NAME AS ReferencedTable,
                                    ku.COLUMN_NAME AS ReferencedColumn
                                 FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS c
                                    INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE cu
                                    ON cu.CONSTRAINT_NAME = c.CONSTRAINT_NAME
                                    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
                                    ON ku.CONSTRAINT_NAME = c.UNIQUE_CONSTRAINT_NAME
                                 WHERE ku.TABLE_NAME = '" + CurrentTableName + "'", DTLinks)

                        NewNode = New HDAS_TreeNode(DTLinks, DT_ItemProperties)

                        TreeView1.Nodes(0).Nodes.Add(NewNode)

                        Exit For

                    End If

                Next

            Next

            TreeView1.ExpandAll()

            DB.Close()

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

#Region "Drag and Drop Process"

#Region "Started Step 1"

    Private Sub TreeView1_ItemDrag(sender As Object, e As ItemDragEventArgs) Handles TreeView1.ItemDrag, TreeView2.ItemDrag

        sender.DoDragDrop(e.Item, DragDropEffects.Copy)

    End Sub
#End Region

#Region "Started Step 2"

    Private Sub TreeView1_DragEnter(sender As Object, e As DragEventArgs) Handles TreeView1.DragEnter, TreeView2.DragEnter

        e.Effect = e.AllowedEffect

    End Sub
#End Region

#Region "Started Step 3"

    Private Sub TreeView_DragOver(sender As Object, e As DragEventArgs) Handles TreeView1.DragOver, TreeView2.DragOver

        ' Retrieve the client coordinates of the mouse position.
        Dim targetPoint As Point = sender.PointToClient(New Point(e.X, e.Y))

        ' Select the node at the mouse position.
        sender.SelectedNode = sender.GetNodeAt(targetPoint)

    End Sub
#End Region

#Region "Started Step 4"

    Private Sub TreeView_DragDrop(sender As Object, e As DragEventArgs) Handles TreeView1.DragDrop, TreeView2.DragDrop

        Dim selectedTreeview As TreeView
        selectedTreeview = CType(sender, TreeView)

        ' Retrieve the client coordinates of the drop location.
        Dim targetPoint As Point = sender.PointToClient(New Point(e.X, e.Y))

        ' Retrieve the node at the drop location.
        Dim targetNode As HDAS_TreeNode = sender.GetNodeAt(targetPoint)

        ' Retrieve the node that was dragged.
        Dim draggedNode As HDAS_TreeNode = CType(e.Data.GetData(GetType(HDAS_TreeNode)), HDAS_TreeNode)

        Dim DroppedNode As HDAS_TreeNode = draggedNode

        If Not draggedNode.Equals(targetNode) AndAlso Not ContainsNode(draggedNode, targetNode) Then

            If targetNode Is Nothing Then

                draggedNode.Remove() 'The Problem is here....If I remove this line I can not Keep Both Nodes
                selectedTreeview.Nodes.Add(DroppedNode.DeepCopy())
            Else
                draggedNode.Remove() 'The Problem is here....If I remove this line I can not Keep Both Nodes
                targetNode.Nodes.Add(DroppedNode.DeepCopy())
            End If

            draggedNode.EnsureVisible()
            selectedTreeview.SelectedNode = draggedNode
            sender.ExpandAll()

        End If

    End Sub

    Private Function ContainsNode(ByVal node1 As HDAS_TreeNode, ByVal node2 As HDAS_TreeNode) As Boolean
        Try

            ' Check the parent node of the second node.
            If node2.Parent Is Nothing Then
                Return False
            End If
            If node2.Parent.Equals(node1) Then
                Return True
            End If

            ' If the parent node is not null or equal to the first node, 
            ' call the ContainsNode method recursively using the parent of 
            ' the second node.
            Return ContainsNode(node1, node2.Parent)

        Catch ex As Exception

        End Try
    End Function 'ContainsNode

#End region

#Region"Here is my CUSTOM TreeNode Class"

Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

<Serializable> Public Class HDAS_TreeNode
    Inherits TreeNode

    Private NodeName As String
    Private NodeText As String

    Private CurrentTableName As String
    Private CurrentTablePrimaryKeys As List(Of String)

    Private LinkedTableNames As List(Of String)
    Private LinkedTableForeignerKeys As List(Of String)

    Private PropertiesFromDB As DataTable

    Private M_DTLinks As New DataTable
    Private M_DTProperties As New DataTable

#Region "Constructor"

    Public Sub New()


    End Sub

    Sub New(DTLinks As DataTable, DTProperties As DataTable)

        M_DTLinks = DTLinks
        M_DTProperties = DTProperties

        Me.Name = HDAS_NodeName
        Me.Text = HDAS_NodeText

        Me.CurrentTableName = HDAS_CurrentTable
        Me.CurrentTablePrimaryKeys = HDAS_PrimaryKeys

        Me.LinkedTableNames = HDAS_LinkedTables
        Me.LinkedTableForeignerKeys = HDAS_ForeignerKeys

        Me.PropertiesFromDB = HDAS_PropertiesFromDB

    End Sub

#End Region

#Region "Properties"

    Public Property HDAS_NodeName As String
        Get
            Return MyNodeName(M_DTProperties)
        End Get
        Set(value As String)
            NodeName = value
        End Set
    End Property

    Public Property HDAS_NodeText As String
        Get
            Return MyNodeText(M_DTProperties)
        End Get
        Set(value As String)
            NodeText = value
        End Set
    End Property

    Public Property HDAS_CurrentTable As String
        Get
            Return MyNodeCurrentTable(M_DTLinks)
        End Get
        Set(value As String)
            CurrentTableName = value
        End Set
    End Property

    Public Property HDAS_PrimaryKeys As List(Of String)
        Get
            Return MyNodePrimaryKeys(M_DTLinks)
        End Get
        Set(value As List(Of String))
            CurrentTablePrimaryKeys = value
        End Set
    End Property

    Public Property HDAS_LinkedTables As List(Of String)
        Get
            Return MyNodeLinkedTableName(M_DTLinks)
        End Get
        Set(value As List(Of String))
            LinkedTableNames = value
        End Set
    End Property

    Public Property HDAS_ForeignerKeys As List(Of String)
        Get
            Return MyNodeForeignerKeys(M_DTLinks)
        End Get
        Set(value As List(Of String))
            LinkedTableForeignerKeys = value
        End Set
    End Property

    Public Property HDAS_PropertiesFromDB As DataTable
        Get
            Return M_DTProperties
        End Get
        Set(value As DataTable)
            PropertiesFromDB = value
        End Set
    End Property

#End Region

#Region "Methods"

    Private Function MyNodeName(DTProperties As DataTable) As String
        Try
            For i As Integer = 0 To DTProperties.Columns.Count

                If DTProperties.Columns(i).ColumnName = "Name" Then

                    MyNodeName = DTProperties.Rows(0).Item(i)

                    Return MyNodeName

                End If

            Next
        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodeName" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Private Function MyNodeText(DTProperties As DataTable) As String
        Try
            For i As Integer = 0 To DTProperties.Columns.Count

                If DTProperties.Columns(i).ColumnName = "Name" Then

                    MyNodeText = DTProperties.Rows(0).Item(i)

                    Return MyNodeText

                End If

            Next
        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodeText" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Private Function MyNodeCurrentTable(M_DTLinks As DataTable) As String
        Try

            MyNodeCurrentTable = M_DTLinks.Rows(0).Item(3)

            Return MyNodeCurrentTable

        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodeCurrentTable" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Private Function MyNodePrimaryKeys(M_DTLinks As DataTable) As List(Of String)

        Try

            Dim LinkedTableList As List(Of String) = Nothing

            MyNodePrimaryKeys = Nothing


            If M_DTLinks.Rows.Count > 1 Then
                LinkedTableList = New List(Of String)

                For i As Integer = 0 To M_DTLinks.Rows.Count - 1

                    Dim LinkedTableName As String = M_DTLinks.Rows(i).Item(4)
                    LinkedTableList.Add(LinkedTableName)

                Next

                MyNodePrimaryKeys = LinkedTableList

                Return MyNodePrimaryKeys

            Else

                MyNodePrimaryKeys = M_DTLinks.Rows(0).Item(4)

                Return MyNodePrimaryKeys

            End If

        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodePrimaryKeys" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Private Function MyNodeLinkedTableName(M_DTLinks As DataTable) As List(Of String)

        Try

            Dim LinkedTableList As List(Of String) = Nothing

            MyNodeLinkedTableName = Nothing


            If M_DTLinks.Rows.Count > 1 Then
                LinkedTableList = New List(Of String)

                For i As Integer = 0 To M_DTLinks.Rows.Count - 1

                    Dim LinkedTableName As String = M_DTLinks.Rows(i).Item(1)
                    LinkedTableList.Add(LinkedTableName)

                Next

                MyNodeLinkedTableName = LinkedTableList

                Return MyNodeLinkedTableName

            Else

                MyNodeLinkedTableName = M_DTLinks.Rows(0).Item(1)

                Return MyNodeLinkedTableName

            End If

        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodeLinkedTableName" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Private Function MyNodeForeignerKeys(M_DTLinks As DataTable) As List(Of String)

        Try

            Dim LinkedTableList As List(Of String) = Nothing

            MyNodeForeignerKeys = Nothing


            If M_DTLinks.Rows.Count > 1 Then
                LinkedTableList = New List(Of String)

                For i As Integer = 0 To M_DTLinks.Rows.Count - 1

                    Dim LinkedTableName As String = M_DTLinks.Rows(i).Item(2)
                    LinkedTableList.Add(LinkedTableName)

                Next

                MyNodeForeignerKeys = LinkedTableList

                Return MyNodeForeignerKeys

            Else

                MyNodeForeignerKeys = M_DTLinks.Rows(0).Item(2)

                Return MyNodeForeignerKeys

            End If

        Catch ex As Exception
            MsgBox("Class Name: HDAS_TreeNode" + vbNewLine + "Method_Name: MyNodeForeignerKeys" + vbNewLine + "Error_Name: " + ex.Message)
        End Try
    End Function

    Public Function DeepCopy() As HDAS_TreeNode
        Dim theClone As HDAS_TreeNode = DirectCast(Me.MemberwiseClone(), HDAS_TreeNode)
        theClone.HDAS_NodeName = String.Copy(HDAS_NodeName)
        theClone.HDAS_NodeText = String.Copy(HDAS_NodeText)
        theClone.HDAS_CurrentTable = String.Copy(HDAS_CurrentTable)
        theClone.HDAS_PrimaryKeys = New List(Of String)(HDAS_PrimaryKeys)
        theClone.HDAS_LinkedTables = New List(Of String)(HDAS_LinkedTables)
        theClone.HDAS_ForeignerKeys = New List(Of String)(HDAS_ForeignerKeys)
        theClone.HDAS_PropertiesFromDB = PropertiesFromDB.Copy
        Return theClone
    End Function

#End Region

End Class

What I expect is to have the Custom TreeNode in both TreeViews after the Drag and Drop process and methods to use Shallow and DeepCopy from my CUSTOM TreeNode. Please colleagues, I really need this...I am almost without sleep because of this. Any hint will be really appreciated. I am new doing all those things and sorry if I didn't made myself clear, English is not my native language. If you need additional explanation, feel free to ask, I am here to learn from you.

标签: vb.netvisual-studio

解决方案


Do not inherit HDAS_TreeNode from TreeNode. Use the standard TreeNode, but store in its TreeNode.Tag property, instances of HDAS_TreeNode. So when you copy nodes between TreeView's, you will end up with different TreeNode instances pointing to the same HDAS_TreeNode instance via their Tag property.

In other words, instead of inheritance, use composition.


推荐阅读