Treeview Remove Checkbox by Some Nodes

TreeView Remove CheckBox by some Nodes

In the code you've shown, you are handling the drawing yourself for all of the nodes whose type is either 5 or 6. For the rest of the types, you're simply allowing the system to draw the nodes in the default way. That's why they all have the lines as expected, but the ones you're owner-drawing do not: You forgot to draw in the lines! You see, when you say e.DrawDefault = false; it's assumed that you really do mean it. None of the regular drawing is done, including the standard lines.

You'll either need to draw in those lines yourself, or figure out how to get by without owner-drawing at all.

From the code you have now, it looks like you're trying to simulate the system's native drawing style as much as possible in your owner-draw code, so it's not clear to me what exactly you accomplish by owner-drawing in the first place. If you're just trying to keep checkboxes from showing up for type 5 and 6 nodes (which, like the lines, are simply not getting drawn because you aren't drawing them!), there's a simpler way to do that without involving owner drawing.


So, you ask, what is that simpler way to hide the checkboxes for individual nodes? Well, it turns out that the TreeView control itself actually supports this, but that functionality is not exposed in the .NET Framework. You need to P/Invoke and call the Windows API to get at it. Add the following code to your form class (make sure you've added a using declaration for System.Runtime.InteropServices):

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);
}

All of the messy stuff at the top are your P/Invoke declarations. You need a handful of constants, the TVITEM structure that describes the attributes of a treeview item, and the SendMessage function. At the bottom is the function you'll actually call to do the deed (HideCheckBox). You simply pass in the TreeView control and the particular TreeNode item from which you want to remove the checkmark.

So you can remove the checkmarks from each of the child nodes to get something that looks like this:

   TreeView with checkmarks hidden for child nodes

Is there a way to remove a check box from a root node in a Tree View Control in C#?

Here I have a solution that may help you. You can solve this problem via redrawing and
"SendMessage".

private void Form1_Load(object sender, EventArgs e)
{
this.treeView1.CheckBoxes = true;
this.treeView1.DrawMode = TreeViewDrawMode.OwnerDrawAll;
this.treeView1.DrawNode += new DrawTreeNodeEventHandler(treeViewGroupStatements_DrawNode);
// root1
TreeNode root1 = new TreeNode();
root1.Text = "root1";
TreeNode node11 = new TreeNode();
node11.Text = "11";
TreeNode node12 = new TreeNode();
node12.Text = "12";
root1.Nodes.Add(node11);
root1.Nodes.Add(node12);
treeView1.Nodes.Add(root1);
// root2
TreeNode root2 = new TreeNode();
root2.Text = "root2";
TreeNode node21 = new TreeNode();
node21.Text = "21";
TreeNode node22 = new TreeNode();
node22.Text = "22";
root2.Nodes.Add(node21);
root2.Nodes.Add(node22);
treeView1.Nodes.Add(root2);

// get all root nodes
foreach (var item in treeView1.Nodes)
{
if(((TreeNode)item).Level == 0)
{
HideList.Add(((TreeNode)item).Text, true);
}
}
}

// define a dictionary to store the root
public Dictionary<string, bool> HideList = new Dictionary<string, bool>();

private void treeViewGroupStatements_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
HideLevelOfTreeView(e.Node);
e.DrawDefault = true;
}

private void HideLevelOfTreeView(TreeNode tn)
{
if (HideList.ContainsKey(tn.Text))
HideCheckBox(tn.TreeView, tn);
}

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;
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);
}

[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);

The test result,

Sample Image

Is it possible to remove some checkboxes from tree view's nodes?

The tree control uses state images to draw the checkboxes. According to the docs on the TVS_CHECKBOXES style:

State image 1 is the unchecked box and state image 2 is the checked
box. Setting the state image to zero removes the check box altogether.

So something like this should let you remove the check box from a tree item:

TVITEM tvi;
tvi.hItem = hTreeItem;
tvi.mask = TVIF_STATE;
tvi.stateMask = TVIS_STATEIMAGEMASK;
tvi.state = 0;
TreeView_SetItem(hWndTree, &tvi);

How to hide checkbox of the certain TreeNode in TreeView control using C#4.0 Win Form Application?

This article explains on how you can hide the checbox of a certain node in a treeview.

Update

Explanation and code from the article:

Currently, there is not build-in support to get this done. But we can send
a TVM_SETITEM message to the treeview control, set TVITEM structure's state
field to 0, and TVITEM's hItem field to the treenode's handle. Then this
treenode will be got rid of the checkbox.

Sample code lists below:

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

public 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")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

private void button1_Click(object sender, System.EventArgs e)
{
TVITEM tvi=new TVITEM();
tvi.hItem=this.treeView1.SelectedNode.Handle;
tvi.mask=TVIF_STATE;
tvi.stateMask = TVIS_STATEIMAGEMASK;
tvi.state=0;
IntPtr lparam=Marshal.AllocHGlobal(Marshal.SizeOf(tvi));
Marshal.StructureToPtr(tvi, lparam, false);
SendMessage(this.treeView1.Handle, TVM_SETITEM, IntPtr.Zero, lparam);
}

This code hides the selected treenode's checkbox and it works well on my
side. You may copy and paste in your project to have a test.

How can I disable a treenode checkbox?

You didn't specify exactly what you want if a TreeNode is disabled. Do you only want some special colouring, or do you want something with the Checked state and the subnodes if a TreeNode becomes disabled?

So you want a TreeNode with some special behaviour?

In you OO class you learned that if you want something that has almost the same behaviour as something else, you should consider to derive one from another.

class TreeNodeThatCanBeDisabled : TreeNode // TODO: invent proper name
{
// Coloring when enabled / disabled
public Color EnabledForeColor {get; set;} = base.ForeColor;
public Color EnabledBackColor {get; set;} = base.BackColor;
public Color DisabledForeColor {get; set;} = ...
public Color DisabledBackColor {get; set;} = ...

private bool isEnabled = true;

public bool IsEnabled
{
get => this.isEnable;
set
{
it (this.IsEnabled = value)
{
// TODO: set the colors
this.isEnabled = value;
}
}
}
}

Maybe you want to raise an event when IsEnabled changes, I'm not sure whether it is wise to do this per node:

public event EventHandler IsEnabledChanged;
protected virtual void OnEnabledChanged(EventHandle e)
{
this.IsEnabledChanged?.Invoke(this, e);
}

Call this in IsEnabled Set.

Furthermore: what do you want with the checkmark? And should all subNodes also be disabled?

foreach (TreeNodeThatCanBeDisabled subNode in this.Nodes.OfType<TreeNodeThatCanBeDisabled())
{
subNode.IsEnabled = value;
}

And I think you should create a TreeNodeView that can enable / disable several TreeNodes at a time, and that can give you all Enabled / Disabled nodes.

TODO: decide whether this special TreeNodeView may contain only TreeNodesThatCanBeDisabled, or also standard TreeNodes.

class TreeNodeViewThatCanHoldTreeNodesThatCanBeDisabled : TreeNodeView // TODO: proper name
{
// Coloring when enabled / disabled
public Color EnabledForeColor {get; set;} = base.ForeColor;
public Color EnabledBackColor {get; set;} = base.BackColor;
public Color DisabledForeColor {get; set;} = ...
public Color DisabledBackColor {get; set;} = ...

public void AddNode(TreeNodeThatCanBeDisabled treeNode)
{
this.Nodes.Add(treeNode);
}

public IEnumerable<TreeNodeThatCanBeDisabled> TreeNodesThatCanBeDisabled =>
base.Nodes.OfType<TreeNodeThatCanBeDisabled>();

public IEnumerable<TreeNodeThatCanBeDisabled> DisabledNodes =>
this.TreeNodesThatCanBeDisabled.Where(node => !node.IsEnabled);

public void DisableAll()
{
foreach (var treeNode in this.TreeNodesThatCanBeDisabled)
treeNode.Enabled = false;
}

TODO: do you only want to change the colors? or also the Checkbox? Collapse / Expand?
Maybe an event that tells you: "hey buddy, this treeNode has become disabled"?

And what if someone clicks on a disabled TreeNode. Should it still collapse / expand, or should it stay in the state that it is:

protected override void OnBeforeExpand (System.Windows.Forms.TreeViewCancelEventArgs e)
{
if (e.Node is TreeNodeThatCanBeDisabled treeNode)
{
// cancel expand if not enabled:
if (!treeNode.IsEnabled)
e.Cancel = true;
}
}

Similar for collapse?

TreeView turn off checkboxes

Working solution can be found here: http://dotnetfollower.com/wordpress/2011/05/winforms-treeview-hide-checkbox-of-treenode/

How to remove checkboxes on specific tree view items with the TVS_CHECKBOXES style

Here is how to create a treeview control with checkboxes and removing checkboxes on select nodes.

First create a window control without the TVS_CHECKBOXES checkbox style. For example :

g_WindowHandleTreeView = CreateWindow(
WC_TREEVIEW,
"",
TVS_TRACKSELECT | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | WS_VISIBLE | TVS_HASBUTTONS,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
550,
g_WindowHandlePannelStructure, // is the parent window control
NULL,
(HINSTANCE)GetWindowLong(g_WindowHandlePannelStructure, GWL_HINSTANCE),
NULL);

Then add the checkbox style :

DWORD dwStyle = GetWindowLong(g_WindowHandleTreeView, GWL_STYLE);
dwStyle |= TVS_CHECKBOXES;
SetWindowLongPtr(g_WindowHandleTreeView, GWL_STYLE, dwStyle);

Now preparing an item for the treeview with an insert struct such as :

TV_INSERTSTRUCT tvinsert = { 0 }; // struct to config the tree control
tvinsert.hParent = TVI_ROOT; // root item
tvinsert.hInsertAfter = TVI_LAST; // last current position
tvinsert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; // attributes
tvinsert.item.stateMask = TVIS_STATEIMAGEMASK;
tvinsert.item.state = 0;
tvinsert.item.pszText = (LPSTR)"Root node";
tvinsert.item.lParam = SOME_ID; // ID for the node

And inserting the node with a SendMessage(...) call :

HTREEITEM Root = (HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert);

The node will display a checkbox at this point (even with item.state set to 0) so all that's left to do is removing it :

TVITEM tvi;
tvi.hItem = Root; // The item to be "set"/modified
tvi.mask = TVIF_STATE;
tvi.stateMask = TVIS_STATEIMAGEMASK;
tvi.state = 0; // setting state to 0 again
TreeView_SetItem(hwnd, &tvi);

That's it.



Related Topics



Leave a reply



Submit