检查TreeView中已检查节点的数量

时间:2009-12-31 02:07:45

标签: c# .net winforms treeview

我是新手使用树视图,我希望能够确保树视图只能检查一个子节点,如果有人试图检查多一个,它会停止检查事件并取消选择所有父节点和子节点。我该怎么做呢?到目前为止,这是我所拥有的,但它表现得很古怪。有什么建议吗?

更新:为了澄清一些事情,这是一个win form treeview,父节点是一个类别,每个类别可以包含多个项目。我只希望用户能够一次从该类别中选择一个类别和一个项目。

private void tvRecipes_BeforeCheck(object sender, TreeViewCancelEventArgs e)
{
    int checkedNodeCount = 0;

    if (e.Node.Parent != null && !e.Node.Parent.Checked)
        e.Cancel = true;
    else
    {
        foreach (TreeNode node in tvRecipes.Nodes)
        {
            if (node.Checked)
                ++checkedNodeCount;

            if (checkedNodeCount > 2)
            {
                MessageBox.Show("Only one recipe can be selected at a time, please deselect the current recipe and try again.", "Too Many Recipes Selected", MessageBoxButtons.OK, MessageBoxIcon.Error);

                e.Cancel = true;
            }
        }
    }
经过一番捣乱,我想出了我追求的解决方案。我在下面发布了它:

private bool CheckNumOfSelectedChildern(TreeViewEventArgs e)
{
    bool Valid = true;
    int selectedChildern = 0;

    foreach (TreeNode node in tvRecipes.Nodes)
    {
        if (node.Checked)
        {
            foreach (TreeNode child in node.Nodes)
            {
                if (child.Checked)
                    ++selectedChildern;
            }
        }
    }

    if (selectedChildern > 1)
    {
        MessageBox.Show("Only one recipe per category can be selected at a time, please deselect the current recipe and try again.", "Too Many Recipes Selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
        e.Node.Checked = false;
        e.Node.Parent.Checked = false;
        Valid = false;
    }       
    return Valid;
}

private bool CheckNumOfSelectedParents(TreeViewEventArgs e)
{
    bool Valid = true;
    int selectedParent = 0;

    foreach (TreeNode root in tvRecipes.Nodes)
    {
        if (root.Checked)
            ++selectedParent;
    }

    if (selectedParent > 1)
    {
        MessageBox.Show("Only one recipe category can be selected at a time, please deselect the current recipe and try again.", "Too Many Recipes Selected", MessageBoxButtons.OK, MessageBoxIcon.Error);
        e.Node.Checked = false;
        Valid = false;
    }
    return Valid;
}

private void tvRecipes_BeforeCheck(object sender, TreeViewCancelEventArgs e)
{
    if (e.Node.Parent != null && !e.Node.Parent.Checked)
        e.Cancel = true;
    else if (e.Node.Checked)
    {
        foreach (TreeNode child in e.Node.Nodes)
        {
            if (child.Checked)
                e.Cancel = true;
        }
    }
}

private void tvRecipes_AfterCheck(object sender, TreeViewEventArgs e)
{
    if (CheckNumOfSelectedParents(e))
    {
        if (e.Node.Parent != null && e.Node.Parent.Checked)
        {
            if (e.Node.Checked)
            {
                if (CheckNumOfSelectedChildern(e))
                {
                    RecipeDs = RetrieveRecipe.FillRecipeDs(e.Node.Text);
                    DataBindControls();
                }                    
            }
            else
            {
                RemoveLabelsFromLayout();
                RemoveDataBindings();
                RecipeDs.Clear();
                this.Refresh();
            }
        }
    }
}

4 个答案:

答案 0 :(得分:1)

仅仅发表评论太长了。

我假设您正在描述标准的Windows窗体TreeView:正确吗?

当你在问题中说:

  

如果有人试图检查更多   一个它停止检查事件和   取消选择所有父节点和子节点。

对我而言,这意味着您有一个能够进行多项选择的树视图,并且标准的Windows窗体TreeView 能够做到这一点。你可以“破解它”,因此它可以进行多项选择:例如:CodeProject : "Multiselect Treeview Implementation",但这样做并非易事。

所以我假设你的意思是“取消选中”父节点和子节点:但后来:这很令人困惑,因为你的问题似乎清楚地询问你如何在一个方面只检查一个子TreeNode时间:这对我来说意味着你永远不会“取消选中”任何其他子节点。

阅读代码时,很明显您正在计划检查一个父节点的可能性,但是您没有明确排除可以检查多个“无父”(根)节点的情况。

因此,建议更清楚地重新陈述您的问题以澄清:

  1. 可以检查多个无父(根)节点吗?

  2. 一次只能检查一个无父(根)节点吗?

  3. 对于每个选中的无父(根)节点,可以同时检查一个且只有一个子节点吗?

  4. 如果子节点“深度嵌套”:这对您有什么影响吗?

  5. 注意:由于本机WinForms TreeView控件的很大限制,我们很多人已经购买了第3个。派对TreeView控件:

    我购买了Integral UI TreeView from Lidor Systems,并对此很满意。 Lidor TreeView的内置属性是'CheckedNodes集合,其中包含所有当前已检查的节点,您可以选择三种选择模式,包括一个“MultiExtended”,允许您进行包含子节点和父节点的非常复杂的选择。任何秩序,在任何“嵌套”级别:

    当然,您可以随时使用包含所有选定节点的“SelectedNodes”集合。

    使用Lidor TreeView,您可以随时(在设计时或运行时)隐藏任何一个节点的CheckBox,CheckBox支持三种状态:'不确定以及'已选中'和未选中。< / p>

    我假设其他第3名。派对TreeView控件也提供了类似的功能,但是当我两年前回顾并尝试了大多数主要版本的“试用版”时:对我而言,Lidor TreeView提供了最大的价值并且并不昂贵。在丰富“样式化”TreeNodes的能力方面,我没有看到任何与“WinForms Universe”中Lidor TreeView的能力相近的东西。披露:我不为Lidor工作,与他们没有业务关系:我只是一个很乐意推荐的客户。

答案 1 :(得分:1)

你的if(checkedNodeCount&gt; 2)...应该在foreach循环之外。

在for循环中,每次都会运行。我假设你的意思是“表演古怪”

也许你应该提供一些关于不正确行为的更多细节。

答案 2 :(得分:1)

希望这有效:

private int _callCountUp;

        private int _callCountDn;

private void tvwPermissions_AfterCheck(object sender, System.Windows.Forms.TreeViewEventArgs e)
        {
            bool anyChecked = false;

            if (_callCountDn == 0 && e.Node.Parent != null)
            {
                anyChecked = false;
                foreach (TreeNode childNode in e.Node.Parent.Nodes)
                {
                    if (childNode.Checked)
                    {
                        anyChecked = true;
                        break;
                    }
                }
                _callCountUp += 1;

                if (anyChecked)
                    e.Node.Parent.Checked = true;

                _callCountUp -= 1;
            }

            if (_callCountUp == 0)
            {
                foreach (TreeNode childNode in e.Node.Nodes)
                {
                    _callCountDn += 1;
                    childNode.Checked = e.Node.Checked;
                    _callCountDn -= 1;
                }
            }
        }

答案 3 :(得分:0)

1年前被问过,但there是提示,如何在Treeview中只选择一个节点