I'm new to C# and don't have any programming experience. But I've finish a C# basics.
Now I would like to design a simple tree view by adding parent node and child node.
I would like to add a second child for the Second node, I'm quite stuck here and don't know what's next.
Any ideas?
Here is the code:
private void addParentNode_Click(object sender, EventArgs e)
{
string yourParentNode;
yourParentNode = textBox1.Text.Trim();
treeView2.Nodes.Add(yourParentNode);
}
private void addChildNode_Click(object sender, EventArgs e)
{
string yourChildNode;
yourChildNode = textBox1.Text.Trim();
treeView2.Nodes[0].Nodes.Add(yourChildNode);
}
Sorry I wasn't clear, I'm not sure if I really need this one here:
//treeView1.BeginUpdate();
//treeView1.Nodes.Clear();
What I'm trying to do, is to add Parent Nodes and child node. In my code, I can add several Parent Nodes, but if I want to add a child node, it only add in the first parent node.
I want that if I add a child node, I want to add it to the second parent or third parent.
In my code I only use one treeview here which names as treeview2
Here is the screenshot
this is how my final code looks like:
Before I put the else, I'm getting an error if I don't select anything. So I made it that way that if there is nothing selected it will add the "child node" to the "default node" or (parent1 node). It seems to work good. Thanks guys;-)
//This is for adding a parent node
private void addParentNode_Click(object sender, EventArgs e)
{
treeView2.BeginUpdate();
string yourParentNode;
yourParentNode = textBox1.Text.Trim();
treeView2.Nodes.Add(yourParentNode);
treeView2.EndUpdate();
}
//This is for adding child node
private void addChildNode_Click(object sender, EventArgs e)
{
if (treeView2.SelectedNode != null)
{
string yourChildNode;
yourChildNode = textBox1.Text.Trim();
treeView2.SelectedNode.Nodes.Add(yourChildNode);
treeView2.ExpandAll();
}
//This is for adding the child node to the default node(parent 1 node)
else
{
string yourChildNode;
yourChildNode = textBox1.Text.Trim();
treeView2.Nodes[0].Nodes.Add(yourChildNode);
}
Additional question: Are there any other ways on how the code be better? Because here, I declare the string "yourChildNode" twice. One in the if and other one in the else, are there any simplification?
It's not that bad, but you forgot to call treeView2.EndUpdate() in your addParentNode_Click() method.
You can also call treeView2.ExpandAll() at the end of your addChildNode_Click() method to see your child node directly.
private void addParentNode_Click(object sender, EventArgs e) {
treeView2.BeginUpdate();
//treeView2.Nodes.Clear();
string yourParentNode;
yourParentNode = textBox1.Text.Trim();
treeView2.Nodes.Add(yourParentNode);
treeView2.EndUpdate();
}
private void addChildNode_Click(object sender, EventArgs e) {
if (treeView2.SelectedNode != null) {
string yourChildNode;
yourChildNode = textBox1.Text.Trim();
treeView2.SelectedNode.Nodes.Add(yourChildNode);
treeView2.ExpandAll();
}
}
I don't know if it was a mistake or not but there was 2 TreeViews. I changed it to only 1 TreeView...
EDIT: Answer to the additional question:
You can declare the variable holding the child node name outside of the if clause:
private void addChildNode_Click(object sender, EventArgs e) {
var childNode = textBox1.Text.Trim();
if (!string.IsNullOrEmpty(childNode)) {
TreeNode parentNode = treeView2.SelectedNode ?? treeView2.Nodes[0];
if (parentNode != null) {
parentNode.Nodes.Add(childNode);
treeView2.ExpandAll();
}
}
}
Note: see http://www.yoda.arachsys.com/csharp/csharp2/nullable.html for info about the ?? operator.
May i add to Stormenet example some KISS (Keep It Simple & Stupid):
If you already have a treeView or just created an instance of it:
Let's populate with some data - Ex. One parent two child's :
treeView1.Nodes.Add("ParentKey","Parent Text");
treeView1.Nodes["ParentKey"].Nodes.Add("Child-1 Text");
treeView1.Nodes["ParentKey"].Nodes.Add("Child-2 Text");
Another Ex. two parent's first have two child's second one child:
treeView1.Nodes.Add("ParentKey1","Parent-1 Text");
treeView1.Nodes.Add("ParentKey2","Parent-2 Text");
treeView1.Nodes["ParentKey1"].Nodes.Add("Child-1 Text");
treeView1.Nodes["ParentKey1"].Nodes.Add("Child-2 Text");
treeView1.Nodes["ParentKey2"].Nodes.Add("Child-3 Text");
Take if farther - sub child of child 2:
treeView1.Nodes.Add("ParentKey1","Parent-1 Text");
treeView1.Nodes["ParentKey1"].Nodes.Add("Child-1 Text");
treeView1.Nodes["ParentKey1"].Nodes.Add("ChildKey2","Child-2 Text");
treeView1.Nodes["ParentKey1"].Nodes["ChildKey2"].Nodes.Add("Child-3 Text");
As you see you can have as many child's and parent's as you want and those can have sub child's of child's and so on....
Hope i help!
Example of adding child nodes:
private void AddExampleNodes()
{
TreeNode node;
node = treeView1.Nodes.Add("Master node");
node.Nodes.Add("Child node");
node.Nodes.Add("Child node 2");
node = treeView1.Nodes.Add("Master node 2");
node.Nodes.Add("mychild");
node.Nodes.Add("mychild");
}
It looks like you are only adding children to the first parent treeView2.Nodes[0].Nodes.Add(yourChildNode)
Depending on how you want it to behave, you need to be explicit about the parent node you wish to add the child to.
For Example, from your screenshot, if you wanted to add the child to the second node you would need:
treeView2.Nodes[1].Nodes.Add(yourChildNode)
If you want to add the children to the currently selected node, get the TreeView.SelectedNode and add the children to it.
Try TreeView to get an idea of how the class operates. Unfortunately the msdn documentation is pretty light on the code samples...
I'm missing a whole lot of safety checks here!
Something like (untested):
private void addChildNode_Click(object sender, EventArgs e) {
TreeNode ParentNode = treeView2.SelectedNode; // for ease of debugging!
if (ParentNode != null) {
ParentNode.Nodes.Add("Name Of Node");
treeView2.ExpandAll(); // so you can see what's been added
treeView2.Invalidate(); // requests a redraw
}
}
I needed to do something similar and came across the same issues. I used the AfterSelect event to make sure I wasn't getting the previously selected node.
It's actually really easy to reference the correct node to receive the new child node.
private void TreeView1_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
//show dialogbox to let user name the new node
frmDialogInput f = new frmDialogInput();
f.ShowDialog();
//find the node that was selected
TreeNode myNode = TreeView1.SelectedNode;
//create the new node to add
TreeNode newNode = new TreeNode(f.EnteredText);
//add the new child to the selected node
myNode.Nodes.Add(newNode);
}
Guys use this code for adding nodes and childnodes for TreeView from C# code.
*
KISS (Keep It Simple & Stupid :)*
protected void Button1_Click(object sender, EventArgs e)
{
TreeNode a1 = new TreeNode("Apple");
TreeNode b1 = new TreeNode("Banana");
TreeNode a2 = new TreeNode("gree apple");
TreeView2.Nodes.Add(a1);
TreeView2.Nodes.Add(b1);
a1.ChildNodes.Add(a2);
}
void treeView(string [] LineString)
{
int line = LineString.Length;
string AssmMark = "";
string PartMark = "";
TreeNode aNode;
TreeNode pNode;
for ( int i=0 ; i<line ; i++){
string sLine = LineString[i];
if ( sLine.StartsWith("ASSEMBLY:") ){
sLine = sLine.Replace("ASSEMBLY:","");
string[] aData = sLine.Split(new char[] {','});
AssmMark = aData[0].Trim();
//TreeNode aNode;
//aNode = new TreeNode(AssmMark);
treeView1.Nodes.Add(AssmMark,AssmMark);
}
if( sLine.Trim().StartsWith("PART:") ){
sLine = sLine.Replace("PART:","");
string[] pData = sLine.Split(new char[] {','});
PartMark = pData[0].Trim();
pNode = new TreeNode(PartMark);
treeView1.Nodes[AssmMark].Nodes.Add(pNode);
}
}
You may do as follows to Populate treeView with parent and child node. And also with display and value member of parent and child nodes:
arrayRoot = taskData.GetRocordForRoot(); // iterate through database table
for (int j = 0; j <arrayRoot.length; j++) {
TreeNode root = new TreeNode(); // Creating new root node
root.Text = "displayString";
root.Tag = "valueString";
treeView1.Nodes.Add(root); //Adding the root node
arrayChild = taskData.GetRocordForChild();// iterate through database table
for (int i = 0; i < arrayChild.length; i++) {
TreeNode child = new TreeNode(); // creating child node
child.Text = "displayString"
child.Tag = "valueString";
root.Nodes.Add(child); // adding child node
}
}
SqlConnection con = new SqlConnection(#"Data Source=NIKOLAY;Initial Catalog=PlanZadanie;Integrated Security=True");
SqlCommand cmd = new SqlCommand();
DataTable dt = new DataTable();
public void loadTree(TreeView tree)
{
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT [RAZDEL_ID],[NAME_RAZDEL] FROM [tbl_RAZDEL]";
try
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
tree.Nodes.Add(reader.GetString(1));
tree.Nodes[0].Nodes.Add("yourChildNode");
tree.ExpandAll();
}
con.Close();
}
catch (Exception ex)
{
MessageBox.Show("Ошибка с сообщением: " + ex.Message);
}
}
You can improve that code
private void Form1_Load(object sender, EventArgs e)
{
/*
D:\root\Project1\A\A.pdf
D:\root\Project1\B\t.pdf
D:\root\Project2\c.pdf
*/
List<string> n = new List<string>();
List<string> kn = new List<string>();
n = Directory.GetFiles(#"D:\root\", "*.*", SearchOption.AllDirectories).ToList();
kn = Directory.GetDirectories(#"D:\root\", "*.*", SearchOption.AllDirectories).ToList();
foreach (var item in kn)
{
treeView1.Nodes.Add(item.ToString());
}
for (int i = 0; i < treeView1.Nodes.Count; i++)
{
n = Directory.GetFiles(treeView1.Nodes[i].Text, "*.*", SearchOption.AllDirectories).ToList();
for (int zik = 0; zik < n.Count; zik++)
{
treeView1.Nodes[i].Nodes.Add(n[zik].ToString());
}
}
}
void tree()
{
int counter = 0;
int counter1 = 0;
int counter2 = 0;
treeView1.Nodes.Clear();
var node = db.ChartOfAccounts.
Include(c => c.chartOfAccounts)
.Where(c => c.parent_account == null).ToList();
foreach (var account in node)
{
treeView1.Nodes.Add(account.account_title);
var node1 = db.ChartOfAccounts
.Where(c => c.parent_account == account.c_id).ToList();
bool t1 = db.ChartOfAccounts.Any(c => c.parent_account == account.c_id);
if (!t1) { counter = counter + 1; }
else
{
foreach (var item in node1)
{ treeView1.Nodes[(counter)].Nodes.Add(item.account_title);
bool test1 = db.ChartOfAccounts
.Any(c => c.parent_account == item.c_id);
if (!test1) { counter1 = counter1 + 1; }
else {
var node2 = db.ChartOfAccounts
.Where(c => c.parent_account == item.c_id).ToList();
foreach (var item2 in node2)
{
treeView1.Nodes[counter].Nodes[(counter1)].Nodes.Add(item2.account_title);
bool test2 = db.ChartOfAccounts
.Any(c => c.parent_account == item2.c_id);
if (!test2) { counter2 = counter2 + 1; }
else
{
var node3 = db.ChartOfAccounts
.Where(c => c.parent_account == item2.c_id).ToList();
foreach (var item3 in node3)
{ treeView1.Nodes[counter].Nodes[counter1].Nodes[counter2].Nodes.Add(item3.account_title); }
}
}
}
}
counter = counter + 1;
}
}
}
Related
I have an asp Treeview which i made for my understanding.
I would like to capture all the check and uncheck checkboxes node user selects.
I have tried to use a button click event in which i check for a CheckNodes. But i would like to know how to get the UnSelected nodes before he click the Save Button.
As per code,
This is the format of my treeview
On Page Load only 3 nodes are checked.
What if the user unselects few node and presses the save button.
How do i know capture the information of checkbox selected/Unselect on postback.
User Action
Selects -- Head1Child1GrandChild1
Unselects -- Head1Child2 &&
Head1Child3
Expected Result : Need to capture checkbox
Selects -- Head1Child1 && Head1Child1GrandChild1 (Code in Save_Click)
AND Also need to capture
Unselects -- Head1Child2 &&
Head1Child3
The given treeview is just a prototype to understand the problem for me. Imagine if there is 1000 nodes and user selects some node and unselects the selected node . I just want to get those unselected and selected node only. Thats it.
Thank you for your time.
<body>
<form id="form1" runat="server">
<div>
<asp:TreeView ID="TreeView1" ShowCheckBoxes="All" Showlines="true" runat="server"></asp:TreeView>
<asp:Button ID="Button1" runat="server" OnClick="Save_Click" Text="Save" />
<br />
</div>
</form>
</body>
//CS Code
//TreeView on a PageLoad.
//It will create TreeView with all Checkbox checked
// If the user Unselects one check box how do i capture that in a event ?
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostback)
{
TreeNode tNode1 = new TreeNode();
tNode1.Text = "HeadNode1";
tNode1.Value = "HeadNode1";
TreeNode h1ChildNode1 = new TreeNode();
h1ChildNode1.Text = "Head1Child1";
tNode1.ChildNodes.Add(h1ChildNode1);
TreeNode h1GrandChild1 = new TreeNode();
h1GrandChild1.Text = "Head1Child1Grand1";
h1ChildNode1.ChildNodes.Add(h1GrandChild1);
TreeNode h1ChildNode2 = new TreeNode();
h1ChildNode2.Text = "Head1Child2";
tNode1.ChildNodes.Add(h1ChildNode2);
TreeNode h1ChildNode3 = new TreeNode();
h1ChildNode3.Text = "Head1Child3";
tNode1.ChildNodes.Add(h1ChildNode3);
TreeView1.Nodes.Add(tNode1);
TreeNode tNode2 = new TreeNode();
tNode2.Text = "HeadNode2";
tNode2.Value = "HeadNode2";
TreeView1.Nodes.Add(tNode2);
ServerSideChangeSelection(TreeView1, true);
}
protected TreeView ServerSideChangeSelection(TreeView t, bool check)
{
foreach (TreeNode tn in t.Nodes)
{
tn.Checked = false;
if (tn.ChildNodes.Count > 0)
{
foreach (TreeNode childNd in tn.ChildNodes)
{
childNd.Checked = check;
}
}
}
return t;
}
}
//Save Button Click for CheckNodes. Missing UnSelect Nodes ??
protected void Save_Click(object sender, EventArgs e)
{
List<string> checkNodes = new List<string>();
List<string> unCheckNodes = new List<string>();
foreach (var item in TreeView1.CheckedNodes)
{
checkNodes.Add(item.ToString());
}
}
I will make some changes to your code:
Created a property like below:
public List<TreeNode> Nodes
{
get
{
if (HttpContext.Current.Session["Nodes"] == null)
{
HttpContext.Current.Session["Nodes"] = new List<TreeNode>();
}
return HttpContext.Current.Session["Nodes"] as List<TreeNode>;
}
set
{
HttpContext.Current.Session["Nodes"] = value;
}
}
In your page_load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TreeNode tNode1 = new TreeNode();
tNode1.Text = "HeadNode1";
tNode1.Value = "HeadNode1";
TreeNode h1ChildNode1 = new TreeNode();
h1ChildNode1.Text = "Head1Child1";
tNode1.ChildNodes.Add(h1ChildNode1);
TreeNode h1GrandChild1 = new TreeNode();
h1GrandChild1.Text = "Head1Child1Grand1";
h1ChildNode1.ChildNodes.Add(h1GrandChild1);
TreeNode h1ChildNode2 = new TreeNode();
h1ChildNode2.Text = "Head1Child2";
tNode1.ChildNodes.Add(h1ChildNode2);
TreeNode h1ChildNode3 = new TreeNode();
h1ChildNode3.Text = "Head1Child3";
tNode1.ChildNodes.Add(h1ChildNode3);
TreeView1.Nodes.Add(tNode1);
TreeNode tNode2 = new TreeNode();
tNode2.Text = "HeadNode2";
tNode2.Value = "HeadNode2";
TreeView1.Nodes.Add(tNode2);
ServerSideChangeSelection(TreeView1, true);
List<TreeNode> nodes = new List<TreeNode>();
foreach (TreeNode node in TreeView1.Nodes)
{
nodes.Add(node);
if (node.ChildNodes.Count > 0)
{
foreach (TreeNode childNode in node.ChildNodes)
{
nodes.Add(childNode);
}
}
}
Nodes = nodes;
}
}
Save_Click:
protected void Save_Click(object sender, EventArgs e)
{
List<TreeNode> unCheckNodes = new List<TreeNode>();
GetCheckUncheckTreeNodes(TreeView1.Nodes, ref unCheckNodes);
}
private void GetCheckUncheckTreeNodes(TreeNodeCollection nodeCollection, ref List<TreeNode> unCheckNodes)
{
if (Nodes != null)
{
foreach (TreeNode node in nodeCollection)
{
if (!node.Checked && Nodes.Any(x => x.Text == node.Text && x.Checked != node.Checked))
unCheckNodes.Add(node);
if (node.ChildNodes.Count > 0)
GetCheckUncheckTreeNodes(node.ChildNodes, ref unCheckNodes);
}
}
}
On Selecting a particular I want to highlight the treepath with nodes as bold one.
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
HighlightPath(Trv.SelectedNode);
}
private void HighlightPath(TreeNode node)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
if (node.Parent != null)
HighlightPath(node.Parent);
}
But next time if I am slelecting another node its should mark previous nodes unbold and new path as bolded one. Please help on this.
You can solve this by stroring all highlighted nodes in a List<TreeNode> and before highlighting a new path, you un-highligt the items in the list.
// New list of currently highlighted nodes
protected List<TreeNode> highlightedNodes = new List<TreeNode>();
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
// Call the method to un-highligt first
UnHighlightNodes();
HighlightPath(Trv.SelectedNode);
}
private void UnHighlightNodes()
{
foreach(var node in highlightedNodes)
{
// TODO: code to un-highlight nodes
}
// Clear List of highlighted nodes
highlightedNodes.Clear();
}
private void HighlightPath(TreeNode node)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
if (node.Parent != null)
HighlightPath(node.Parent);
// Store the node in the list of highlighted nodes
highlightedNodes.Add(node);
}
This could be optimized further to prevent un-highlighting and then immediatley highlighting again. Like this:
// New list of currently highlighted nodes
protected List<TreeNode> HighlightedNodes = new List<TreeNode>();
protected void Trv_SelectedNodeChanged(object sender, EventArgs e)
{
var nodesToHighlight = FindPathToRoot(Trv.SelectedNode).ToList();
// Un-highlight nodes (except those which should stay highlighted)
UnHighlightNodes(HighlightedNodes.Except(nodesToHighlight));
// Highlight nodes (except nodes already highlighted)
HighlightNodes(nodesToHighlight.Except(HighlightedNodes));
// Save the new list of highlighted nodes;
HighlightedNodes = nodesToHighlight;
}
private static IEnumerable<TreeNode> FindPathToRoot(TreeNode node)
{
do
{
yield return node;
node = node.Parent;
} while (node != null);
}
private void UnHighlightNodes(IEnumerable<TreeNode> nodes)
{
foreach (var node in nodes)
{
// TODO: code to un-highlight nodes
}
}
private void HighlightNodes(IEnumerable<TreeNode> nodes)
{
foreach (var node in nodes)
{
node.SelectAction = TreeNodeSelectAction.None;
node.Text = "<div style=font-weight:bold>" + node.Text + "</div>";
}
}
I think you need to bold selected node and its Parent node in a treeview asp.net page.
If its so you don't need to make it complex. Please try to put this in your page load event as shown .
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
foreach (TreeNode ParentNodes in TreeView1.Nodes)
{
ParentNodes.Text = ParentNodes.Text.Replace("<b>", "").Replace("</b>", "");
foreach (TreeNode ChildNodes in ParentNodes.ChildNodes)
{
ChildNodes.Text = ChildNodes.Text.Replace("<b>", "").Replace("</b>", "");
}
}
TreeNode node = TreeView1.SelectedNode;
node.Text = Server.HtmlDecode("<b>" + node.Text + "</b>");
node.Parent.Text = Server.HtmlDecode("<b>" + node.Parent.Text + "</b>");
}
}
Here TreeView1 is my treeview . You don't need to do anything in SelectedNodeChanged event for this.
I have a Treeview with checkboxes when I click the parent node checkbox that child node will also be checked
I want to get the checked child node value
In the below code I got all the checked values even parent node value
But I don't want that parent node.
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
Session["listActivity"] = listActivity;
}
}
}
In the above image I don't want to get HR Activity(Parent node)
Any ideas? Thanks in advance
Use the following code. The main parent node does not have a parent.
You only need to set the session variable at the end of the foreach
Keep in mind that accesing or assigning session variables means that a deserialization/serialization of the object is happening
Also I dont know if maybe you need to clear or initialize the listActivity before the foreach. You can do this either with
listActivity = new List<ActivityData>() ;
or
listActivity.Clear();
Here is the code
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
//The main parent node does not have a parent
if(node.Parent != null)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
}
}
//stablish the session variable only when the foreach has finished
Session["listActivity"] = listActivity;
}
}
There's a property of a treeview node called Level, so you could skip nodes with a level of 0, course that will break down if you nest a level deeper.
If you know which parent node it is, then iterate through it's children and test for checked.
protected void btnAdd_Click(object sender, EventArgs e)
{
if (TreeView1.CheckedNodes.Count > 0)
{
foreach (TreeNode node in TreeView1.CheckedNodes)
{
if (node.Level > 0)
{
string checkedValue = node.Text.ToString();
activityData = new ActivityData { ActivityName = checkedValue };
listActivity.Add(activityData);
Session["listActivity"] = listActivity;
}
}
}
}
I am using Ext.net TreePanel which does not have an option to skip the root node.
Basically, I have the following code
protected void Page_Load(object sender, EventArgs e)
{
SiteMapNode siteNode = SiteMap.RootNode;
Ext.Net.TreeNode root = this.CreateNode(siteNode);
root.Draggable = false;
root.Expanded = true;
TreePanel1.Root.Add(root);
}
private Ext.Net.TreeNode CreateNode(SiteMapNode siteMapNode)
{
Ext.Net.TreeNode treeNode = new Ext.Net.TreeNode();
treeNode.NodeID = siteMapNode.Key;
treeNode.Text = siteMapNode.Title;
treeNode.Qtip = siteMapNode.Description;
SiteMapNodeCollection children = siteMapNode.ChildNodes;
if (children != null && children.Count > 0)
{
foreach (SiteMapNode mapNode in siteMapNode.ChildNodes)
{
treeNode.Nodes.Add(this.CreateNode(mapNode));
}
}
return treeNode;
}
Could you please help to skip the parent node in the above example.
Thank you and regards.
A Root Node is required, although you can set RootVisible="false" on your <ext:TreePanel /> to hide it.
Hope this helps.
I am trying to dynamically add controls to an asp.net page. The page is rendering correctly but after posting back, I get the following error:
[HttpException (0x80004005): Multiple controls with the same
ID 'ParentTextBox_ChildTextBox_TV_PostRender' were found. FindControl requires that controls have unique IDs.]
System.Web.UI.Control.FillNamedControlsTable(Control namingContainer, ControlCollection controls) +273
System.Web.UI.Control.EnsureNamedControlsTable() +61
System.Web.UI.Control.FindControl(String id, Int32 pathOffset) +222
System.Web.UI.Control.FindControl(String id, Int32 pathOffset) +327
System.Web.UI.Page.FindControl(String id) +38
System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad) +232
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1434
I have tried several different things a none of which work. I thought removing the control in OnInit or on page_load like this
Control c = Page.FindControl("ParentTextBox_ChildTextBox_TV_PostRender");
Page.Controls.Remove(c);
will work but it doesn't
Code of custom tree view control
// file ContainerTreeView.cs
using System.Web.UI;
using System.Web.UI.WebControls;
using System;
namespace DASHBOARD
{
[ToolboxData("<{0}:ContainerTreeView runat=server></{0}:ContainerTreeView>")]
public class ContainerTreeView : TreeView, INamingContainer
{
public ContainerTreeView()
: base()
{
PathSeparator = ClientIDSeparator;
}
protected override void OnInit(EventArgs e)
{
// Initialize Child Controls
RecurseUpdateNodes(Nodes);
base.OnInit(e);
}
protected const String s_strNodeValueSeparator = "_TV_";
protected virtual void RecurseUpdateNodes(TreeNodeCollection parrNodes)
{
if (parrNodes == null || parrNodes.Count == 0)
return;
foreach (TreeNode pNode in parrNodes)
{
ContainerTreeNode pContainerNode = pNode as ContainerTreeNode;
if (pContainerNode != null)
{
// update node pre / post rendering control IDs id
if (pContainerNode.PreRenderContainer != null)
{
pContainerNode.PreRenderContainer.ID = pContainerNode.PreRenderContainer.ID.Insert(0, pNode.ValuePath + s_strNodeValueSeparator);
Controls.Add(pContainerNode.PreRenderContainer);
}
if (pContainerNode.PostRenderContainer != null)
{
pContainerNode.PostRenderContainer.ID = pContainerNode.PostRenderContainer.ID.Insert(0, pNode.ValuePath + s_strNodeValueSeparator);
Controls.Add(pContainerNode.PostRenderContainer);
}
}
// update children
RecurseUpdateNodes(pNode.ChildNodes);
}
}
public ContainerTreeNode CreateTreeNode()
{
return new ContainerTreeNode(this, false);
}
protected override TreeNode CreateNode()
{
return CreateTreeNode();
}
// collection of child controls
protected override ControlCollection CreateControlCollection()
{
return new ControlCollection(this);
}
protected override void RenderChildren(HtmlTextWriter writer)
{
// do not render children as they will be rendered within treeview nodes
// base.RenderChildren(writer);
}
}
}
This is the page where I am adding the tree:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
namespace DASHBOARD
{
public partial class testTreeEdit : System.Web.UI.Page
{
ContainerTreeView m_pTreeView = null;
protected override void OnInit(EventArgs e)
{
Control c = Page.FindControl("ParentTextBox_ChildTextBox_TV_PostRender");
Page.Controls.Remove(c);
tb.Text += "Removed Control";
base.OnInit(e);
}
#region main
protected void Page_Load(object sender, EventArgs e)
{
if (CheckBox1.Checked)
{
renderEditTree();
}
else
{
makeTree();
TreeView1.ExpandAll();
}
}
#endregion
#region editableTreeView
/** //function to render editable tree view
protected void renderEditTree()
{
m_pTreeView = new ContainerTreeView();
ContainerTreeNode pNodeParent = m_pTreeView.CreateTreeNode();
pNodeParent.Value = "Parent";
pNodeParent.Text = "Parent";
pNodeParent.Expanded = true;
m_pTreeView.Nodes.Add(pNodeParent);
/**ContainerTreeNode pNodeChildDropDown = m_pTreeView.CreateTreeNode();
pNodeChildDropDown.Value = "ChildDropDown";
pNodeChildDropDown.Text = String.Empty;
DropDownList pList = new DropDownList();
pList.ID = "ID_DropDown";
pList.Items.Add("AAA");
pList.Items.Add("BBB");
pList.Items.Add("CCC");
pNodeChildDropDown.PostRenderControls.Add(pList);
pNodeParent.ChildNodes.Add(pNodeChildDropDown);
/**ContainerTreeNode pNodeChildButton = m_pTreeView.CreateTreeNode();
pNodeChildButton.Value = "ChildButton";
pNodeChildButton.Text = String.Empty;
Button pButton = new Button();
pButton.ID = "ID_Button";
pButton.Text = "PostBack";
pNodeChildButton.PostRenderControls.Add(pButton);
pNodeParent.ChildNodes.Add(pNodeChildButton);
/** ContainerTreeNode pNodeChildTextBox = m_pTreeView.CreateTreeNode();
pNodeChildTextBox.Value = "ChildTextBox";
pNodeChildTextBox.Text = String.Empty;
TextBox pTextBox = new TextBox();
pTextBox.ID = "ID_TextBox";
pTextBox.Text = "Some text";
pNodeChildTextBox.PostRenderControls.Add(pTextBox);
pNodeParent.ChildNodes.Add(pNodeChildTextBox);
this.treeViewContainer.Controls.Add(m_pTreeView);
}*/
//load XML file and use it to make the tree view
public void renderEditTree()
{
m_pTreeView = new ContainerTreeView();
XDocument document = XDocument.Load(Server.MapPath("~/Releases_files/releases.xml"));
foreach (XElement element in document.Descendants("Release"))
{
XName name0 = "version";
XAttribute a0 = element.Attribute(name0);
string temp0 = a0.Value;
ContainerTreeNode pmTextBox = m_pTreeView.CreateTreeNode();
pmTextBox.Value = "ParentTextBox";
pmTextBox.Text = String.Empty;
TextBox pTextBox = new TextBox();
pTextBox.ID = temp0;
pTextBox.Text = temp0;
pmTextBox.PostRenderControls.Add(pTextBox);
m_pTreeView.Nodes.Add(pmTextBox);
//n0.Text = temp0;
//TreeView1.Nodes.Add(n0);
foreach (XElement myElement in element.Descendants("Feature"))
{
XName name = "Name";
XAttribute a = myElement.Attribute(name);
string temp = a.Value;
ContainerTreeNode pcTextBox = m_pTreeView.CreateTreeNode();
pcTextBox.Value = "ChildTextBox";
pcTextBox.Text = String.Empty;
TextBox p2TextBox = new TextBox();
p2TextBox.ID = temp;
p2TextBox.Text = temp;
pcTextBox.PostRenderControls.Add(p2TextBox);
pmTextBox.ChildNodes.Add(pcTextBox);
}
this.treeViewContainer.Controls.Add(m_pTreeView);
}
}
#endregion
#region simpleTreeView
//old code
//load XML file and use it to make the tree view
public void makeTree()
{
TreeView1.Nodes.Clear();
XDocument document = XDocument.Load(Server.MapPath("~/Releases_files/releases.xml"));
foreach (XElement element in document.Descendants("Release"))
{
TreeNode n0 = new TreeNode();
XName name0 = "version";
XAttribute a0 = element.Attribute(name0);
string temp0 = a0.Value;
n0.Text = temp0;
TreeView1.Nodes.Add(n0);
foreach (XElement myElement in element.Descendants("Feature"))
{
TreeNode n = new TreeNode();
XName name = "Name";
XAttribute a = myElement.Attribute(name);
string temp = a.Value;
n.Text = temp;
n0.ChildNodes.Add(n);
}
}
}
//action to do when selected node is changed
protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
XDocument document = XDocument.Load(Server.MapPath("~/Releases_files/releases.xml"));
//debug
//Label1.Text = TreeView1.SelectedNode.Text;
//Label5.Text = Convert.ToString(TreeView1.SelectedNode.Depth);
//case1: feature selected
if (TreeView1.SelectedNode.Depth > 0)
{
string featureName = TreeView1.SelectedNode.Text;
string releaseName = TreeView1.SelectedNode.Parent.Text;
foreach (XElement element in document.Descendants("Release"))
{
//find the right release in XML
XName name = "version";
XAttribute a = element.Attribute(name);
string versionAttribute = a.Value;
if (releaseName.Equals(versionAttribute))
{
foreach (XElement myElement in element.Descendants("Feature"))
{
//find the right feature in XML
XName name1 = "Name";
XAttribute a1 = myElement.Attribute(name1);
string versionAttribute1 = a1.Value;
if (featureName.Equals(versionAttribute1))
{
//found the right node, now populate the Fields
IEnumerable<XElement> dates = element.Descendants("Date");
XElement date = dates.First<XElement>();
Label5.Text = date.Value;
IEnumerable<XElement> statuses = element.Descendants("Status");
XElement status = statuses.First<XElement>();
Label6.Text = status.Value;
IEnumerable<XElement> types = myElement.Descendants("Type");
XElement type = types.First<XElement>();
Label7.Text = type.Value;
IEnumerable<XElement> developers = myElement.Descendants("Developer");
XElement developer = developers.First<XElement>();
Label8.Text = developer.Value;
IEnumerable<XElement> details = myElement.Descendants("Detail");
XElement detail = details.First<XElement>();
tb.Text = detail.Value;
}
}
}
}
}
//case2: Release selected
else
{
string releaseName = TreeView1.SelectedNode.Text;
foreach (XElement element in document.Descendants("Release"))
{
//find the right release in XML
XName name = "version";
XAttribute a = element.Attribute(name);
string versionAttribute = a.Value;
if (releaseName.Equals(versionAttribute))
{
//found the right node, now populate the Fields
IEnumerable<XElement> dates = element.Descendants("Date");
XElement date = dates.First<XElement>();
Label5.Text = date.Value;
IEnumerable<XElement> statuses = element.Descendants("Status");
XElement status = statuses.First<XElement>();
Label7.Text = " ";
Label8.Text = " ";
tb.Text = " ";
}
}
}
}
#endregion
#region userInputs
protected void Button2_Click(object sender, EventArgs e)
{
}
//edit tree check box
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
if (CheckBox1.Checked )//&& TreeView1.Visible==true)
{
TreeView1.Visible = false;
if (m_pTreeView != null)
{
m_pTreeView.Visible = true;
}
Label5.Enabled = false;
Label6.Enabled = false;
Label7.Enabled = false;
Label8.Enabled = false;
tb.Enabled = false;
}
else
{
TreeView1.Visible = true;
if (m_pTreeView != null)
{
m_pTreeView.Visible = false;
}
Label5.Enabled = true;
Label6.Enabled = true;
Label7.Enabled = true;
Label8.Enabled = true;
tb.Enabled = true;
}
}
#endregion
}
}
I may be misunderstanding the code a bit, but if the PreRenderContainer and PostRenderContainer properties implement INamingcontainer and you change their IDs, I think you might not be letting them do their job. It should automatically give you unique ids. Like ctl00, ctl01 etc...
You need to set the ID property of the control to some unique value before adding it to the page. There are a number of tricks you can use to make this work out. If you provide more code, we can provide some ideas for solutions tailored to your situation.
Edit
It looks like you've got some pretty complicated stuff going on here, so I'm not grokking it fully. However, I'd look at setting the IDs of your ContainerTreeNodes when they're instantiated, rather than during the OnInit phase. I'd also make the ContainerTreeNode architecture support a means of traversing and removing a node within itself, rather than trying to manually remove a node based on a Control ID from outside the tree.