Results 1 to 8 of 8

Thread: Treenode Added Event

  1. #1

    Thread Starter
    Lively Member
    Join Date
    May 2008
    Location
    Perth, Australia
    Posts
    101

    Treenode Added Event

    I am trying to create a NodeAdded event for a treeview. Is this possible and if so, where would be a good start point?

  2. #2

    Thread Starter
    Lively Member
    Join Date
    May 2008
    Location
    Perth, Australia
    Posts
    101

    Re: Treenode Added Event

    I should probably add that I have looked at creating a custom TreeNodeCollection and overide Add(TreeNode Node), but the TreeView.Nodes is a Read-only property.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: Treenode Added Event

    My advice would be to inherit the TreeView class and override the WndProc method, then see if there is a particular message or set of messages that correspond to nodes being added and/or removed.

  4. #4
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Treenode Added Event

    Quote Originally Posted by jmcilhinney View Post
    My advice would be to inherit the TreeView class and override the WndProc method, then see if there is a particular message or set of messages that correspond to nodes being added and/or removed.
    I had this problem in the past and it never occurred to me to override WndProc. Thanks to your suggestion I was able to produce a TreeView that raises events when nodes are added or deleted:-
    vbnet Code:
    1. Public Class TreeViewEx
    2.     Inherits TreeView
    3.  
    4.     Public Event NodeAdded As EventHandler
    5.     Public Event NodeRemoved As EventHandler
    6.  
    7.  
    8.     Protected Overridable Sub OnNodeAdded(ByVal e As EventArgs)
    9.         RaiseEvent NodeAdded(Me, e)
    10.     End Sub
    11.  
    12.     Protected Overridable Sub OnNodeRemoved(ByVal e As EventArgs)
    13.         RaiseEvent NodeRemoved(Me, e)
    14.     End Sub
    15.  
    16.     Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    17.  
    18.         If m.Msg = 4402 Then
    19.             OnNodeAdded(New EventArgs)
    20.         End If
    21.  
    22.         'I had to choose between 4414 and 4353
    23.         'the number of 4414 messages correlate with
    24.         'the amount of nodes removed so Im 97% certain its
    25.         'the message sent to remove nodes. 4353 Fires only once
    26.         'no matter how many nodes are removed but its related somehow
    27.         '----- Niya
    28.         If m.Msg = 4414 Then
    29.             OnNodeRemoved(New EventArgs)
    30.         End If
    31.  
    32.         MyBase.WndProc(m)
    33.     End Sub
    34.  
    35. End Class
    Note however that as of yet I'm retrieve a reference to the node that was added or deleted, so beware of that limitation. Also note that those magic numbers were obtained by me sort of guessing which messages meant to Add/Delete so there might be a circumstance where it may prove that I was wrong. I did a simple Add/Delete test and it seems to correlate especially 4414 but im not 100% certain so be aware of that also.

  5. #5
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: Treenode Added Event

    Rather than using raw numbers, it's generally preferred to declare a constant that uses the actual message name. If you call ToString on the Message object then, in most cases, it should display the message name, e.g. WM_CLICK for a click message. Once you know what message that you're actually dealing with, then you can look it up on MSDN or elsewhere on the web and see how it can be used. You may well find that the WParam or LParam provide access to the node itself somehow.

  6. #6
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Treenode Added Event

    Actually in this case m.ToString doesnt reveal a name however about 5 minutes after I posted that code above, I was able to locate their declarations in NativeMethods.cs after finding the actual constant names for the values on an MSDN page. I was quite surprised to know that I actually got the numbers right.

    Im currently working on a way to retrieve the node that the Add/Remove operation was performed on. Its just a little tricky....got to work with a structure that contains a union(Yuck!! makes everything more confusing) with some strange _Win32_IE macro or compiler directive around it but once I can figure how to ".NET" that sucker properly, I should be able to retrieve a handle which I can use to search the TreeView's nodes for. I'll post it up as soon as I succeed. Wish me luck.

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,274

    Re: Treenode Added Event

    Luck wished

  8. #8
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    Re: Treenode Added Event

    Finally got it after pounding away at this for a couple hours.
    Ok here we go:-
    vbnet Code:
    1. Imports System.Runtime.InteropServices
    2.  
    3. 'typedef struct tagTVITEMEX {
    4. '  UINT      mask;
    5. '  HTREEITEM hItem;
    6. '  UINT      state;
    7. '  UINT      stateMask;
    8. '  LPTSTR    pszText;
    9. '  int       cchTextMax;
    10. '  int       iImage;
    11. '  int       iSelectedImage;
    12. '  int       cChildren;
    13. '  LPARAM    lParam;
    14. '  int       iIntegral;
    15. '#if (_WIN32_IE >= 0x0600)
    16. '  UINT      uStateEx;
    17. '  HWND      hwnd;
    18. '  int       iExpandedImage;
    19. '#End If
    20. '#If (NTDDI_VERSION >= NTDDI_WIN7) Then
    21. '  int       iReserved;
    22. '#End If
    23. '} TVITEMEX, *LPTVITEMEX;
    24. <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    25. Public Structure TVITEMEX
    26.     Public mask As UInteger
    27.     Public hItem As IntPtr
    28.     Public state As UInteger
    29.     Public stateMask As UInteger
    30.     Public pszText As String
    31.     Public cchTextMax As Integer
    32.     Public iImage As Integer
    33.     Public iSelectedImage As Integer
    34.     Public cChildren As Integer
    35.     Public lParam As Integer
    36.     Public iIntegral As Integer
    37.     Public uStateEx As UInteger
    38.     Public hwnd As IntPtr
    39.     Public iExpandedImage As Integer
    40.  
    41.     'Not sure if this should be defined
    42.     'What the flying ***** is NTDDI_WIN7 anyways ?
    43.     Public iReserved As Integer
    44. End Structure
    45.  
    46. 'typedef struct {
    47. '  HTREEITEM hParent;
    48. '  HTREEITEM hInsertAfter;
    49. '#if (_WIN32_IE >= 0x0400)
    50. '  union {
    51. '    TVITEMEX itemex;
    52. '    TVITEM   item;
    53. '  } DUMMYUNIONNAME;
    54. '#Else
    55. '  TVITEM    item;
    56. '#End If
    57. '} TVINSERTSTRUCT, *LPTVINSERTST
    58. <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
    59. Public Structure TVInsertStruct
    60.     Public hParent As IntPtr
    61.     Public hInsertAfter As IntPtr
    62.  
    63.     <MarshalAs(UnmanagedType.Struct)> _
    64.     Public itemEx As TVITEMEX
    65.  
    66. End Structure
    67.  
    68.  
    69. Public Class TreeViewEx
    70.     Inherits TreeView
    71.  
    72.     Private Const TVM_GETITEMW = (&H1100 + 62)
    73.     Private Const TVM_SETITEMW = (&H1100 + 63)
    74.  
    75.     'Use:-
    76.     'ins = Marshal.PtrToStructure(m.LParam, GetType(TVInsertStruct))
    77.     'to get the Structure used to insert the item
    78.     Private Const TVM_INSERTITEMW = (&H1100 + 50)
    79.  
    80.     Private Const TVM_DELETEITEM = (&H1100 + 1)
    81.     Private Const TVIF_HANDLE = (&H10)
    82.  
    83.     Private g_lstRemNodes As New List(Of TreeNode)
    84.  
    85.     Public Event NodeAdded As EventHandler(Of NodeAddedEventArgs)
    86.     Public Event NodesRemoved As EventHandler(Of NodesRemovedEventArgs)
    87.  
    88.     Protected Overridable Sub OnNodeAdded(ByVal e As NodeAddedEventArgs)
    89.         RaiseEvent NodeAdded(Me, e)
    90.     End Sub
    91.  
    92.     Protected Overridable Sub OnNodesRemoved(ByVal e As NodesRemovedEventArgs)
    93.         RaiseEvent NodesRemoved(Me, e)
    94.     End Sub
    95.  
    96.     Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    97.         MyBase.WndProc(m)
    98.  
    99.         Dim it As TVITEMEX
    100.  
    101.         'I've only observed this message being sent
    102.         'presumably to select several nodes(1 message per node)
    103.         'before deleting them
    104.         If m.Msg = TVM_GETITEMW Then
    105.             it = Marshal.PtrToStructure(m.LParam, GetType(TVITEMEX))
    106.  
    107.             If it.hItem <> IntPtr.Zero Then
    108.                 Dim n As TreeNode = FindNodeByHandle(it.hItem)
    109.                 g_lstRemNodes.Add(n)
    110.             End If
    111.  
    112.         End If
    113.  
    114.         'GETITEM messages sent before would have identified the nodes
    115.         'that are going to be deleted.
    116.         'IMPORTANT!!!!!
    117.         'I cannot be certain that there are not other circumstances where
    118.         'GETITEM messages would be sent. If this happens then there probably
    119.         'will be nodes in the list that were not actually deleted.
    120.         If m.Msg = TVM_DELETEITEM Then
    121.             OnNodesRemoved(New NodesRemovedEventArgs(g_lstRemNodes.ToArray))
    122.             g_lstRemNodes.Clear()
    123.         End If
    124.  
    125.         If m.Msg = TVM_SETITEMW Then
    126.             it = Marshal.PtrToStructure(m.LParam, GetType(TVITEMEX))
    127.  
    128.             'The handle of a TreeNode object is ReadOnly so
    129.             'there is no way that .Net code can assign a handle
    130.             'to a TreeNode object. Only the TreeView's low level
    131.             'code does therefor when it happens it could only
    132.             'mean that a node was just added to the treeview
    133.             If it.mask And TVIF_HANDLE Then
    134.                 If it.hItem <> IntPtr.Zero Then
    135.                     OnNodeAdded(New NodeAddedEventArgs(FindNodeByHandle(it.hItem)))
    136.                 End If
    137.             End If
    138.         End If
    139.     End Sub
    140.  
    141.     Private Function FindNodeByHandle(ByVal handle As IntPtr) As TreeNode
    142.  
    143.         For Each N As TreeNode In GetAllTreeNodes(Me.Nodes)
    144.             If N.Handle = handle Then Return N
    145.         Next
    146.  
    147.         Return Nothing
    148.     End Function
    149.  
    150.     Private Function GetAllTreeNodes(ByVal baseCollection As TreeNodeCollection) As TreeNode()
    151.         Dim al As New List(Of TreeNode)(100)
    152.  
    153.         For Each N As TreeNode In baseCollection
    154.             al.Add(N)
    155.             If N.Nodes.Count > 0 Then al.AddRange(GetAllTreeNodes(N.Nodes))
    156.         Next
    157.  
    158.         Return al.ToArray
    159.     End Function
    160.  
    161. End Class
    162.  
    163.  
    164. Public Class NodeAddedEventArgs
    165.     Inherits EventArgs
    166.  
    167.     Private _node As TreeNode
    168.  
    169.     Public Sub New(ByVal n As TreeNode)
    170.         _node = n
    171.     End Sub
    172.     Public ReadOnly Property Node() As TreeNode
    173.         Get
    174.             Return _node
    175.         End Get
    176.     End Property
    177. End Class
    178.  
    179. Public Class NodesRemovedEventArgs
    180.     Inherits EventArgs
    181.  
    182.     Private _RemovedNodes As TreeNode()
    183.     Private _cancel As Boolean = False
    184.  
    185.     Public Sub New(ByVal nodes As TreeNode())
    186.         _RemovedNodes = nodes
    187.     End Sub
    188.  
    189.     Public ReadOnly Property RemovedNodes() As TreeNode()
    190.         Get
    191.             Return _RemovedNodes
    192.         End Get
    193.     End Property
    194.  
    195.  
    196. End Class
    I've altered the NodeAdded and NodesRemoved events from my earlier example to both return references to EventArgs parameters that reference the node or nodes affected. And I've also resolved those magic numbers to the actual constant names defined by MS and oh boy, hunting them wasnt easy. Anyways enjoy

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width