0
votes

I am using the following solution to show or hide checkboxes in a TreeView:

https://stackoverflow.com/a/22230299/1583649

However, now i would like to know how to check if the checkbox is hidden or not for the node.

For example, i want to be able to set checkbox.checked to true (or false) on only the children of a top-level node that have a checkbox visible when the top-level node is checked. Is there a way to do this?

1
None of that is necessary. Simply use the TreeNode.StateImageIndex property. Set it to -1 to hide the fake checkbox, to 0 or 1 to pick one of the state images. Reading it back is now trivial as well of course.Hans Passant
wait are you saying that i don't need to user Interop to hide the checkbox itself?MaxOvrdrv
i tried your answer Hans and it simply didn't work... sorry.MaxOvrdrv

1 Answers

2
votes

TVM_GETITEM or TVM_GETITEMSTATE can be used to get the state, which can then be used to deduce which checkbox image (none, checked or unchecked) is on the node. Here's an extension class that provides the two methods you need.

USAGE:

// something like this
var treeNode = ...;
if (treeNode.IsCheckBoxVisible())
    treeNode.SetIsCheckBoxVisible(false);
else
    treeNode.SetIsCheckBoxVisible(true);

EXTENSIONS:

public static class TreeViewExtensions
{
    /// <summary>
    /// Gets a value indicating if the checkbox is visible on the tree node.
    /// </summary>
    /// <param name="node">The tree node.</param>
    /// <returns><value>true</value> if the checkbox is visible on the tree node; otherwise <value>false</value>.</returns>
    public static bool IsCheckBoxVisible(this TreeNode node)
    {
        if (node == null)
            throw new ArgumentNullException("node");
        if (node.TreeView == null)
            throw new InvalidOperationException("The node does not belong to a tree.");
        var tvi = new TVITEM
            {
                hItem = node.Handle,
                mask = TVIF_STATE
            };
        var result = SendMessage(node.TreeView.Handle, TVM_GETITEM, node.Handle, ref tvi);
        if (result == IntPtr.Zero)
            throw new ApplicationException("Error getting TreeNode state.");
        var imageIndex = (tvi.state & TVIS_STATEIMAGEMASK) >> 12;
        return (imageIndex != 0);
    }

    /// <summary>
    /// Sets a value indicating if the checkbox is visible on the tree node.
    /// </summary>
    /// <param name="node">The tree node.</param>
    /// <param name="value"><value>true</value> to make the checkbox visible on the tree node; otherwise <value>false</value>.</param>
    public static void SetIsCheckBoxVisible(this TreeNode node, bool value)
    {
        if (node == null)
            throw new ArgumentNullException("node");
        if (node.TreeView == null)
            throw new InvalidOperationException("The node does not belong to a tree.");
        var tvi = new TVITEM
            {
                hItem = node.Handle,
                mask = TVIF_STATE,
                stateMask = TVIS_STATEIMAGEMASK,
                state = (value ? node.Checked ? 2 : 1 : 0) << 12
            };
        var result = SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
        if (result == IntPtr.Zero)
            throw new ApplicationException("Error setting TreeNode state.");
    }

    private const int TVIF_STATE = 0x8;
    private const int TVIS_STATEIMAGEMASK = 0xF000;
    private const int TV_FIRST = 0x1100;
    private const int TVM_GETITEM = TV_FIRST + 62;
    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);
}