3、当一个节点的所有子节点都没有被选中时,该节点也没有被选中。
4、当一个节点的所有子节点中有一个被选中时,则该节点也被选中。
代码中对事件参数e.Action的判断,可以避免在改变节点的Checked的状态时,再次进入AfterCheck(),这样当在AfterCheck()中有其他逻辑响应时,可以做到每次勾选时,其他逻辑也只响应一次。
参考代码:
private void treeView_AfterCheck(object sender, TreeViewEventArgs e)
//通过鼠标或者键盘触发事件,防止修改节点的Checked状态时候再次进入
if (e.Action == TreeViewAction.ByMouse || e.Action == TreeViewAction.ByKeyboard)
SetChildNodeCheckedState(e.Node, e.Node.Checked);
SetParentNodeCheckedState(e.Node, e.Node.Checked);
//设置子节点状态
private void SetChildNodeCheckedState(TreeNode currNode, bool isCheckedOrNot)
if (currNode.Nodes == null) return; //没有子节点返回
foreach (TreeNode tmpNode in currNode.Nodes)
tmpNode.Checked = isCheckedOrNot;
SetChildNodeCheckedState(tmpNode, isCheckedOrNot);
//设置父节点状态
private void SetParentNodeCheckedState(TreeNode currNode, bool isCheckedOrNot)
if (currNode.Parent == null) return; //没有父节点返回
if (isCheckedOrNot) //如果当前节点被选中,则设置所有父节点都被选中
currNode.Parent.Checked = isCheckedOrNot;
SetParentNodeCheckedState(currNode.Parent, isCheckedOrNot);
else //如果当前节点没有被选中,则当其父节点的子节点有一个被选中时,父节点被选中,否则父节点不被选中
bool checkedFlag = false;
foreach (TreeNode tmpNode in currNode.Parent.Nodes)
if (tmpNode.Checked)
checkedFlag = true;
break;
currNode.Parent.Checked = checkedFlag;
SetParentNodeCheckedState(currNode.Parent, checkedFlag);
TreeView隐藏部分节点
WinForm中的TreeView没法根据每个节点的情况设置是否有checkbox,只能用CheckBoxes设置整个树是否有Checkbox,可通过如下方式隐藏部分节点的checkbox。
this.treeView1.CheckBoxes = true;
this.treeView1.DrawMode = TreeViewDrawMode.OwnerDrawAll;
this.treeView1.DrawNode += new DrawTreeNodeEventHandler(treeView1_DrawNode);
隐藏节点:
void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
//隐藏节点前的checkbox
if (e.Node.Level == 0 || e.Node.Level == 1)
HideCheckBox(this.treeView1, e.Node);
e.DrawDefault = true;
[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);
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);
TreeView递归加载节点
C#遍历指定文件夹下所有子文件夹及文件并添加到目录树:
private void Form1_Load(object sender, EventArgs e)
TreeNode root = new TreeNode();
//根目录名称
root.Text = "目录";
//根目录路径
GetFiles(@"E:\Tools", root);
treeView1.Nodes.Add(root);
private void GetFiles(string filePath, TreeNode node)
DirectoryInfo folder = new DirectoryInfo(filePath);
node.Text = folder.Name;
node.Tag = folder.FullName;
FileInfo[] chldFiles = folder.GetFiles("*.*");
foreach (FileInfo chlFile in chldFiles)
TreeNode chldNode = new TreeNode();
chldNode.Text = chlFile.Name;
chldNode.Tag = chlFile.FullName;
node.Nodes.Add(chldNode);
DirectoryInfo[] chldFolders = folder.GetDirectories();
foreach (DirectoryInfo chldFolder in chldFolders)
TreeNode chldNode = new TreeNode();
chldNode.Text = folder.Name;
chldNode.Tag = folder.FullName;
node.Nodes.Add(chldNode);
GetFiles(chldFolder.FullName, chldNode);