简体   繁体   中英

How to make Treeview check only one option

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.

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)

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

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

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.

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

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

在此处输入图片说明

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM