【问题标题】:Check number of checked nodes in TreeView检查 TreeView 中已检查节点的数量
【发布时间】:2009-12-31 02:07:44
【问题描述】:

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

更新:为了澄清一些事情,这是一个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();
            }
        }
    }
}

【问题讨论】:

  • @Nathan,您好,我看到您接受了我的回答,这实际上是一个较长的“评论”,而不是对您问题的具体回答。我不确定我的“长评论'冒充'作为答案”是否值得接受,所以如果你得到“更好的答案”,请不要犹豫选择它。再一次,我可以(温和地)鼓励您稍微澄清一下您的问题。最好的,
  • @Nathan,有几个问题: 1. 根据设计,最终用户无法选中或取消选中类别节点? 2.如果用户可以检查类别(根)节点:但没有在检查的类别节点中选择项目(子节点):这是错误情况吗? 3.只有检查子节点的行为会自动检查根节点,即您刚刚检查的子节点的父节点? 4.如果我被允许取消选中一个类别节点并且我在其父(类别)节点中选中了一个项目节点,当我取消选中项目时ndoe:类别节点(父节点)也必须取消选中?
  • @Nathan,嗨,一旦我们确切知道类别节点(无父节点、根节点)可以做什么和不可以做什么,这种情况可以很容易地用一两个布尔标志来管理,或者,也许,仅通过使用对当前检查的类别节点(无父,根)和当前检查的项目节点(子节点)的两个引用。最好的,
  • 我已经用我在周末想出的答案更新了我的问题。

标签: c# .net winforms treeview


【解决方案1】:

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

在 for 循环中,它每次都会运行。我假设这就是你所说的“表现古怪”的意思

也许您应该更详细地说明不正确的行为是什么。

【讨论】:

    【解决方案2】:

    这太长了,不适合发表评论。

    我假设您描述的是标准的 Windows 窗体 TreeView:对吗?

    当你在你的问题中说:

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

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

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

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

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

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

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

    3. 对于每个检查的无父(根)节点,在任何时候都可以检查一个且只有一个子节点?

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

    注意:由于原生 WinForms TreeView 控件的巨大限制,我们很多人都购买了 3rd。派对 TreeView 控件:

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

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

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

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

    【讨论】:

      【解决方案3】:

      希望这可行:

      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;
                      }
                  }
              }
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多