Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TreeNode.Handle not returning using Treeview

Tags:

c#

treeview

I'm using a treeview with three levels of nodes, the second level which I've set not to have checkboxes using the code in this question.

It works very well except the very first checkbox it encounters never has the checkbox removed:

Example of error

I'm calling the HideCheckBox() method with this code which is after all of the data has been loaded into the treeview:

foreach (TreeNode appNode in trvPermissions.Nodes)
{
      foreach (TreeNode secNode in appNode.Nodes)
      {
         HideCheckBox(trvPermissions, secNode);
      }
}

When I step through the code it seems that node.Handle returns 0 for the first node it encounters and this isn't a valid handle to use when calling the code to remove the checkbox. Oddly enough, if I call the method to remove the checkbox twice then the handle is returned properly.

Can anyone suggest why TreeNode.Handle wouldn't return the correct value?

EDIT:

Here's the code as requested -

    private const int TVIF_STATE = 0x8;
    private const int TVIS_STATEIMAGEMASK = 0xF000;
    private const int TV_FIRST = 0x1100;
    private const int TVM_SETITEM = TV_FIRST + 63;

    [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
    private struct TVITEM
    {
        public int mask;
        public IntPtr hItem;
        public int state;
        public int stateMask;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpszText;
        public int cchTextMax;
        public int iImage;
        public int iSelectedImage;
        public int cChildren;
        public IntPtr lParam;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                             ref TVITEM lParam);

    /// <summary>
    /// Hides the checkbox for the specified node on a TreeView control.
    /// </summary>
    private void HideCheckBox(TreeView tvw, TreeNode node)
    {
        TVITEM tvi = new TVITEM();
        tvi.hItem = node.Handle;
        tvi.mask = TVIF_STATE;
        tvi.stateMask = TVIS_STATEIMAGEMASK;
        tvi.state = 0;
        SendMessage(tvw.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
    }
like image 819
GrandMasterFlush Avatar asked Sep 05 '11 12:09

GrandMasterFlush


1 Answers

The true reason isn't visible in your code. This will fail as described when you call this code from the form constructor. Too early, it can only work when the native TreeView window is created. Not until then does TreeNode.Handle get a value. Using tvw.Handle will trigger the creation of the native window handle, too late to give node.Handle a value for the first node.

Move the code to a Load event handler or OnLoad override.

like image 79
Hans Passant Avatar answered Oct 17 '22 12:10

Hans Passant