带CheckBoxes的慢TreeNode [大量]

时间:2010-08-20 19:25:45

标签: c# winforms checkbox treenode

Tree View控件的AfterCheck事件检查其下面的所有子节点,并在检查某些内容时启用“运行”按钮。

1346 void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) {
1347   if (!e.Node.Checked) return;
1348   foreach (TreeNode sub in e.Node.Nodes) {
1349     sub.Checked = e.Node.Checked;
1350   }
1351   RunButton.Enabled = IsANodeChecked();
1352 }

1429 static bool IsANodeChecked(TreeNode node) {
1430   if (node.Checked) return true;
1431   foreach (TreeNode sub in node.Nodes) {
1432     if (IsANodeChecked(sub)) {
1433       return true;
1434     }
1435   }
1436   return false;
1437 }

当有4881个子节点时检查根节点将挂起GUI大约7秒钟。

我只需要调用IsANodeChecked(在1351行),但我不知道如何在处理完所有树节点之前禁用它。

我不希望在我的表格上有一个专门用来监控它的计时器。

有没有人看到一个简单/明显的解决方案?

3 个答案:

答案 0 :(得分:2)

在您的复选框上放置一个启用或禁用RunButton的事件处理程序,而不是让整个事情迭代以查找。

首先选中复选框,将复选框添加到已选中复选框的列表中,这样在复选复选框列表为空之前,不要禁用RunButton。取消选中时将其从列表中删除等等。

以下是我如何写出来的内容,如果我错过了一些内容,那就太过分了。

private int _checkedCheckboxes;

void AddCheckBox()
{
    if (_checkedCheckBoxes++ == 1) RunButton.Enabled = true;
}

void RemoveCheckBox()
{
    if (_checkedCheckBoxes-- == 0) RunButton.Enabled = false;
}

void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) 
{
    if (e.Node.Checked)
    {
        AddCheckBox();
        return;
    }

    RemoveCheckBox();
}

答案 1 :(得分:1)

我有时使用Timer来处理此类案件。添加计时器并设置Tick事件处理程序以调用IsANodeChecked并启用/禁用该按钮。给它一个短暂的间隔(也许约100毫秒),并将其禁用。然后,在Stop事件处理程序中的计时器上调用Start,然后调用AfterCheck。这将导致每次调用AfterCheck时重新启动计时器,但只有在Tick调用后经过一定时间后才会调用Start事件处理程序,这意味着它在最后一次调用AfterCheck之后才会调用。

100毫秒是计算机工作的非常长时间,但对于用户来说似乎是即时的。

您可以在Windows资源管理器中看到类似的行为。如果使用键盘在文件夹树中快速导航,则除非您短暂停留在树中的文件夹上,否则包含文件夹内容的右侧窗格将不会更新。

答案 2 :(得分:0)

这些想法很有用,但我使用了一些不同的东西,通过添加一个布尔变量来起作用:

bool _treeNodeFirst = false;

...还有一个Before Checked事件,它暂时修改控件上的Back Color,作为启动事件链的控件的标志:

1273 void TreeNode_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
1274   if (!_treeNodeFirst) {
1275     _treeNodeFirst = true;
1276     e.Node.BackColor = Color.Silver;
1277   }
1278 }

1346 void TreeNode_AfterCheck(object sender, TreeViewEventArgs e) {
1347   if (e.Node.Checked) {
1348     foreach (TreeNode sub in e.Node.Nodes) {
1349       sub.Checked = e.Node.Checked;
1350     }
1351   }
1352   if (e.Node.BackColor == Color.Silver) {
1353     e.Node.BackColor = Color.Empty;
1354     RunButton.Enabled = IsANodeChecked();
1355     _treeNodeFirst = false;
1356   }
1357 }

1429 static bool IsANodeChecked(TreeNode node) {
1430   if (node.Checked) return true;
1431   foreach (TreeNode sub in node.Nodes) {
1432     if (IsANodeChecked(sub)) {
1433       return true;
1434     }
1435   }
1436   return false;
1437 }

这似乎是最好的方法(我现在可以看到),以确保IsANodeChecked(TreeNode)仅在一次选择一组节点时运行一次。

然而,我确实非常喜欢Jimmy Hoffa使用计数的想法。我可能会将其添加到我的代码中。

感谢大家! 〜乔