带复选框的慢树节点[大量]

发布于 2024-09-15 12:09:29 字数 751 浏览 7 评论 0原文

树视图控件的 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 行)一次,但我不知道如何禁用它,直到所有树节点都已处理完毕。

我不想在我的表单上有一个专门用于监控这一点的计时器。

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

Tree View control's AfterCheck event checks all child nodes below it and enables the Run button if something is checked.

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 }

Checking the root node when there are 4881 sub nodes will hang the GUI for about 7 seconds.

I only need to call IsANodeChecked (on Line 1351) once, but I don't know how to disable it until after all of the tree nodes have been processed.

And I do not want to have a timer on my form devoted to monitoring this.

Does anyone see a simple/obvious solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

半世晨晓 2024-09-22 12:09:29

在复选框上放置一个事件处理程序来启用或禁用 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();
}

Put an event handler on your checkboxes that enables or disables the RunButton as opposed to having something that iterates over the whole thing to find out.

Add the checkbox to a list of checked checkboxes when it get's checked first so you don't disable the RunButton until the list of checked checkboxes is empty. Remove it from the list when it's unchecked, etc.

Here's kind of how I would write it out, this is just winging it so sorry if I miss something:

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();
}
皇甫轩 2024-09-22 12:09:29

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

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

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

I sometimes use a Timer to handle such cases. Add a timer and set up the Tick event handler to call IsANodeChecked and enable/disable the button. Give it a short interval (~100 ms perhaps), and leave it disabled. Then, you call Stop followed by Start on the timer in your AfterCheck event handler. This will cause the timer to be restarted for each call to AfterCheck, but the Tick event handler will be invoked only when a certain time has elapsed after the Start call, which means that it will not be invoked until after the last call to AfterCheck.

100 ms is a very long time for the computer to work, but will seem immediate for the user.

You can see similar behavior in the Windows Explorer. If you use the keyboard to quickly navigate around in the folder tree, the right hand pane with the folder contents will not update unless you stay on a folder in the tree for a brief moment.

美男兮 2024-09-22 12:09:29

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

bool _treeNodeFirst = false;

...以及一个Before Checked事件,该事件临时修改要服务的控件上的背景颜色作为启动事件链的控件的标志:

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) 仅在一组时运行一次的最佳方法(我现在可以看到)一次性选择所有节点。

不过,我确实很喜欢吉米·霍法使用计数的想法。我可能会将其添加到我的代码中。

感谢大家!
〜乔

These ideas where helpful, but I used something different that worked by adding a single boolean variable:

bool _treeNodeFirst = false;

...and a Before Checked event that temporarily modifies the Back Color on the control to serve as a flag for the control that started the chain of events:

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 }

This seems to be the best way (that I can see right now) to ensure that IsANodeChecked(TreeNode) is only run once when a group of nodes is selected all at once.

I do, however, really like Jimmy Hoffa's idea of using a count, though. I will probably add that to my code.

Thanks to all!
~Joe

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文