2

I have a treeview and Checkbox is set true. What I want is that only one checkbox is selected in the whole treeview. How can I do that?

FYI: the treeview is in three level depth.

Mr.Rendezvous
  • 1,933
  • 5
  • 20
  • 34
  • I found a solution here http://www.codeproject.com/Tips/242364/Select-only-one-node-in-Treeview and it works fine – Hidayath Dec 02 '15 at 19:43

8 Answers8

3

It is an old post, though none of provided solutions is working in my case.

So I did as follows,

private TreeNode uncheck_treeview(TreeView treeView, TreeNode treeNode, TreeViewEventHandler e)
{
    treeView.AfterCheck -= e;

    foreach (TreeNode node in treeView.Nodes)
    {
        uncheck_treenode_tree(node);
    }

    if (treeNode != null)
    {
        treeNode.Checked = true;
    }

    treeView.AfterCheck += e;

    return treeNode;
}

and

private void uncheck_treenode(TreeNode treeNode)
{
    treeNode.Checked = false;
    foreach (TreeNode node in treeNode.Nodes)
    {
        uncheck_treenode_tree(node);
    }
}

and

private void treeView1_AfterCheck(object sender, TreeViewEventArgs e)
{
    var checkedNode = uncheck_treeview_tree((TreeView) sender, e.Node, treeView1_AfterCheck);
    // further processing ...
}

note that this method prevents StackOverflowException !

hope useful to others

anonim
  • 2,494
  • 6
  • 30
  • 40
  • You have to rename the method `uncheck_treenode_tree` to `uncheck_treenode` in order to get the code working. – Fer R Jul 21 '22 at 20:32
3

The simplest way to do that is to set an even handler to your tree view's AfterCheck event. In this handler you can uncheck all the nodes but the one which just became checked:

void node_AfterCheck(object sender, TreeViewEventArgs e) {
    // only do it if the node became checked:
    if (e.Node.Checked) {
        // for all the nodes in the tree...
        foreach (TreeNode cur_node in e.Node.TreeView.Nodes) {
            // ... which are not the freshly checked one...
            if (cur_node != e.Node) {
                // ... uncheck them
                cur_node.Checked = false;
            }
        }
    }
}

Should work (didn't try)

Mr.Rendezvous
  • 1,933
  • 5
  • 20
  • 34
Rom
  • 4,129
  • 23
  • 18
  • After I try, it's only work in first level of node. it's children node not getting unchecked. cmiiw – Mr.Rendezvous Oct 05 '11 at 08:24
  • 4
    Instead of just iterating over the nodes in the TreeView, you need to recursively iterate over ALL the nodes, and uncheck them.... Notice that this is going to be slow in case your TreeView has A LOT of nodes.... – SaguiItay Oct 05 '11 at 08:59
0

I tried it certainly works

       bool manualcheck = false;
      protected override void OnAfterCheck(TreeViewEventArgs e)
      {
                if (manualcheck) return;
                if (e.Node.Checked)
                {
                   if (Nodes.Count>0) UnCheckAll(Nodes[0]);
                   manualcheck = true;
                e.Node.Checked = true;
                manualcheck = false;
                }


        }


        void UnCheckAll(TreeNode node)
            {


                if (node != null)
                {

                    node.Checked = false;
                    foreach (TreeNode item in node.Nodes)
                    {
                        manualcheck = true;
                        item.Checked = false;
                        if (item.Nodes.Count > 0) UnCheckAll(item.Nodes[0]);
                    }


                    if (node.NextNode != null)
                        UnCheckAll(node.NextNode);

                }
                manualcheck = false;
            }
0

I had the same issue, but looping trough all Nodes sounds expensive for performance.

Here is my solution without looping trough all Nodes, but using a class property:

public partial class GuiDefault // not my whole class, just an example
{ 

TreeNode checkedNode = null;

    private void Tree_AfterCheck(object sender, TreeViewEventArgs e)
    {
        TreeNode checkedNodeVar = e.Node;

        if (checkedNodeVar.Checked)
                    {

                        if (checkedNode != null)
                        {
                            checkedNode.Checked = false; // set "checked" property of the last checked box to false
                        }

                        checkedNode = checkedNodeVar; // set the class property "checkedNode" to the currently checked Node
                    }
        else
                    {
                        checkedNode = null; // if current checked box gets unchecked again, also reset the class property "checkedNode"
                    }
    }

}

The only issue i found with this solution is that if the user toggle the same checkbox to fast, the function doesn't get called correctly and it doesnt "check" or "uncheck" the box with 1 click, just after clicking it twice then.

Maybe someone else can add a fix for clicking the same checkbox to fast at runtime.

Kamui
  • 106
  • 1
  • 1
  • 13
0
// Upon node checked, uncheck all other nodes
private void tvAccountHierarchy_AfterCheck(object sender, TreeViewEventArgs e)
    {
        // only do it if the node became checked:
        if (e.Node.Checked)
        {   
            Uncheck_Treenodes(e.Node.TreeView.Nodes, e.Node);                
        }
    }

//Recursively iterate through all child nodes and uncheck all except the checkedNode
 private void Uncheck_Treenodes(TreeNodeCollection treeNodes, TreeNode checkedNode)
    {            
        // iterate through child nodes & uncheck
        foreach (TreeNode cur_node in treeNodes)
        {
            if (cur_node != checkedNode)
            {
                // ... uncheck them
                cur_node.Checked = false;
            }
            Uncheck_Treenodes(cur_node.Nodes, checkedNode);
        }
    }
Todd
  • 1
  • 1
    Please add further details to expand on your answer, such as working code or documentation citations. – Community Sep 02 '21 at 20:26
-1

This solution which I shamelessly stole allows you to iterate over all nodes at all levels in one go.

This makes ensuring only one node is selected easy:

    foreach (var node in resultsTree.GetAllNodes())
    {
        if (node != e.Node) node.Checked = false;
    }
Simon Brooke
  • 162
  • 2
  • 8
-1

I use the solution found here.

A javascript in the page

function client_OnTreeNodeChecked(event)
{
 var treeNode = event.srcElement || event.target ;
 if (treeNode.tagName == "INPUT" && treeNode.type == "checkbox")
  {
   if(treeNode.checked)
    {
     uncheckOthers(treeNode.id);
    }
  }
}

function uncheckOthers(id)
 {
  var elements = document.getElementsByTagName('input');
  // loop through all input elements in form
  for(var i = 0; i < elements.length; i++)
   {
    if(elements.item(i).type == "checkbox")
    {
     if(elements.item(i).id!=id)
     {
      elements.item(i).checked=false;
     }
    }
   }
  }

And code behind to add client_OnTreeNodeChecked function to your treeviews onclick event

private void Page_PreRender(object sender, EventArgs e)
 {
  TreeView1.Attributes.Add("OnClick", "client_OnTreeNodeChecked(event)");
 }

NOTE: read my post How to make javascript work along with Ajax UpdatePanel if TreeView is inside an UpdatePanel

Community
  • 1
  • 1
Emanuele Greco
  • 12,551
  • 7
  • 51
  • 70
-2

enter image description here

        <script type="text/javascript">

    function MakeRadio() {
        var tv = document.getElementById("<%= position_TreeView.ClientID %>");
        var chkArray = tv.getElementsByTagName("input");

        for (i = 0; i <= chkArray.length - 1; i++) {
            if (chkArray[i].type == 'checkbox') {
                chkArray[i].type = 'radio';
                chkArray[i].name = 'YaMahdi';
            }
        }
    }

    window.onload = MakeRadio;

</script>
    <script type="text/javascript">

    function OnTreeClick(evt) {
        var src = window.event != window.undefined ? window.event.srcElement : evt.target;
        var isChkBoxClick = (src.tagName.toLowerCase() == "input" && src.type == "radio");
        if (isChkBoxClick) {
            SelectOne(src.id);
        }
    }


    function SelectOne(objId) {
        var tv = document.getElementById("<%= position_TreeView.ClientID %>");
        var chkArray = tv.getElementsByTagName("input");

        for (i = 0; i <= chkArray.length - 1; i++) {
            if (chkArray[i].type == 'radio') {
                if (chkArray[i].id != objId) {
                    chkArray[i].checked = false;
                }
            }
        }
    }
</script>
mirazimi
  • 814
  • 10
  • 11