问题描述
如果你需要比我提供的更多信息,那么第一篇文章和一个新的编码器就和我一起吧。我正在尝试使用层次结构中的复选框创建树视图(见图)。我的问题是我想创建某种递归,在检查父节点时取消选择和选择子节点,反之亦然。
我正在使用 VS 和 winforms,并在谷歌上搜索了 2 天如何做到这一点,不幸的是,在线示例对我来说要么太先进,要么不起作用。我还找到了关于如何使用不确定的复选框准确执行此操作的 Tutorial,这将是一个很大的好处,但它适用于 WPF。
我设法创建了一些按钮,这些按钮可以通过一些在线示例(取消)检查所有按钮。请有人指导,一个初学者,到目前为止发现编程令人惊叹,朝着正确的方向:)
private void button_checkAllNodes_Click(object sender,EventArgs e)
{
checkAllNodes(treeView1.Nodes);
}
private void button_uncheckAllNodes_Click(object sender,EventArgs e)
{
UncheckAllNodes(treeView1.Nodes);
}
public void checkAllNodes(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = true;
checkChildren(node,true);
}
}
public void UncheckAllNodes(TreeNodeCollection nodes)
{
foreach (TreeNode node in nodes)
{
node.Checked = false;
checkChildren(node,false);
}
}
private void checkChildren(TreeNode rootNode,bool isChecked)
{
foreach (TreeNode node in rootNode.Nodes)
{
checkChildren(node,isChecked);
node.Checked = isChecked;
}
}
private void treeView1_AfterSelect(object sender,TreeViewEventArgs e)
{
}
Picture Treeview with (un)check All buttons
解决方法
让我们为 TreeNode
类型创建几个扩展方法,一个获取节点的所有子节点,另一个获取它的父节点。
// Within your project's namespace...
static class TreeViewExtensions
{
public static IEnumerable<TreeNode> Children(this TreeNode node)
{
foreach (TreeNode n in node.Nodes)
{
yield return n;
foreach (TreeNode child in Children(n))
yield return child;
}
}
public static IEnumerable<TreeNode> Parents(this TreeNode node)
{
var p = node.Parent;
while (p != null)
{
yield return p;
p = p.Parent;
}
}
}
现在,您需要做的就是处理 TreeView.AfterCheck
事件以切换扩展方法产生的节点的 Checked
属性。
// +
using System.Linq;
private void treeView1_AfterCheck(object sender,TreeViewEventArgs e)
{
if (e.Action == TreeViewAction.Unknown) return;
foreach (TreeNode n in e.Node.Children())
n.Checked = e.Node.Checked;
// Comment this if you don't need it.
foreach (TreeNode p in e.Node.Parents())
p.Checked = p.Nodes.OfType<TreeNode>().Any(n => n.Checked);
}
很快,您会注意到,当您快速单击复选框时,有时此解决方案将无法正常工作,因为默认情况下它们不会收到鼠标双击消息。然后,按照this 帖子或this 解决此问题。现在慢慢点击。
如果您更喜欢使用按钮来切换检查状态,请删除 AfterCheck
处理程序并改为执行以下操作:
private void btnCheckAll_Click(object sender,EventArgs e)
{
ToggleCheck(treeView1.SelectedNode,true);
}
private void btnUncheckAll_Click(object sender,false);
}
private void ToggleCheck(TreeNode node,bool state)
{
node.Checked = state;
foreach (TreeNode n in node.Children())
n.Checked = state;
// Optional...
foreach (TreeNode n in node.Parents())
n.Checked = state;
}
,
我同意@jdweng,您在 checkChildren() 中使用递归。缺少基本情况。
在递归 checkChildren 中,在
之前添加基本情况
foreach (TreeNode node in rootNode.Nodes)
if node is Null : rootNode=isChecked