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.
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.
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
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)
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.
// 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);
}
}
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>