I have a TreeView in my Windows Form user interface.
I want to fill it up from a database, but it does not refresh ever, even though if I WriteLine() every node, it is in memory as I expect.
In order to make it more easy to understand, I wrote a little example program that only has one button that creates a TreeView and a TreeView called treeView1 to display its content.
If anyone can tell me where I have misunderstood the use of the TreeView, it would be a tremendous help.
private void button1_Click(object sender, EventArgs e)
{
// create a tree
TreeView t = new TreeView();
TreeNode[] child = new TreeNode [1];
child[0]=new TreeNode("myCat");
child[0].Name = "IndependantOne";
TreeNode categoryNode = new TreeNode("catIdTag", child);
categoryNode.Name = "Citizen Cat 5239002147";
t.Nodes.Add(categoryNode);
// some stuff under the first node
TreeNode[] mouseNode = new TreeNode[1];
mouseNode[0] = new TreeNode("myMouse");
mouseNode[0].Name = "SqueakyOne";
TreeNode[] childItem = new TreeNode[1];
childItem[0] = new TreeNode("mouseIdTag", mouseNode);
childItem[0].Name = "Citizen Mouse 54655654649";
TreeNode eltNode = new TreeNode("Cheese", childItem);
eltNode.Name = "Emmental";
t.Nodes["Citizen Cat 5239002147"].Nodes.Add(eltNode);
// fill in the winform treeview
if (t != null)
{
//treeView1.Visible = false;
treeView1.BeginUpdate();
treeView1.Nodes.Clear();
treeView1.TopNode = t.TopNode;
foreach (TreeNode n in t.Nodes)
{
treeView1.Nodes.Add(n);
System.Diagnostics.Debug.WriteLine("Category Node contains: " + treeView1.Nodes[n.Name].Name + " at " + treeView1.Nodes[n.Name].Level);
foreach (TreeNode no in treeView1.Nodes[n.Name].Nodes)
{
System.Diagnostics.Debug.WriteLine("Category Node Nodes contains: " + no.Name);
}
}
/*
This part I tried and it doesn't work either, still add it in the question if anyone knows if it's wiser?
this.treeView1 = t;
this.treeView1.Location = new System.Drawing.Point(233, 12);
this.treeView1.Name = "treeView1";
this.treeView1.Size = new System.Drawing.Size(351, 277);
this.treeView1.TabIndex = 11;
this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect);
*/
treeView1.EndUpdate();
this.treeView1.Update();
this.treeView1.Refresh();
treeView1.Show();
//this.Refresh();
}
}
I also tried setting the treeView1 with
treeView1 = t;
It was not a success...
change
treeView1.Nodes.Add(n);
with
treeView1.Nodes.Add((TreeNode)n.Clone());
You cannot host the same node in more than one TreeView control.
Alternatively, you can remove nodes from source TreeView before adding them to other TreeView:
while(t.Nodes.Count != 0)
{
var node = t.Nodes[0];
t.Nodes.RemoveAt(0);
treeView1.Nodes.Add(node);
}
And I hope that there is a real reason why you create and fill tree view in your method instead of directly filling an already existing one. If it is not an intended behavior, remove the if block completely and change TreeView t = new TreeView(); to var t = treeView1.
This behavior is expected because with this code you`re confusing node-to-treeview relationship nature of the native .NET treeview control. Instead when moving nodes between treeviews (t -> treeView1) you need to clone them as suggested. Without that moved node still linked with the old treeview (see node.Treeview property) and because original tree (t) is not visible/added to any parent (form), I guess node will be invisible as well.
Also, the way you`re working with data loading (through creating new treeview) is pretty bad pattern. Instead you need to download your data (async I guess) into a temp buffer and recreate the treeView1 at once when data will be available with BeginUpdate/EndUpdate calls.
PS. Replacing treeView1 variable with 't' won't work as well because you don't replace the treeview control instance in the parent form/panel Controls property with this code.
Related
I have a TreeView that is displayed inside a panel. The data in the TreeView is based on data returned from the database. The first time, the data is correct. The second time, the TreeView is not refreshed, and the previous data is still showing in the tree. I checked the list that contain the data. The list returned the correct data. I've Google the issue, and could not resolved it with some of the answers that were posted. Here is a sample code of how the TreeView is being created and added to the Panel.
ReportGroups gr = new ReportGroups();
var Name = gr.GetReportName(groupID);
TreeView tr = new TreeView();
tr.BeginUpdate();
tr.Size = new Size(570, 600);
tr.Name = "Home";
tr.Nodes.Add("Reports Name");
tr.CheckBoxes = true;
if (Name.Count() > 0)
{
foreach (var item in Name)
{
if (item != null)
{
tr.Nodes[0].Nodes.Add(item.reportName);
}
}
}
tr.Nodes[0].ExpandAll();
tr.EndUpdate();
this.pDisplayReportName.Width = tr.Width * 2;
this.pDisplayReportName.Height = 300;
this.pDisplayReportName.Controls.Add(tr);
this.pDisplayReportName.Refresh();
What am I doing wrong?
try to add this.pDisplayReportName.Clear(); so data will not double up. :)
The easy option would be to use this.pDisplayReportName.Controls.Clear(); just after tr.EndUpdate();. But, this would cause an issue if you have other controls within the same Panel.
The best option would be to use this.pDisplayReportName.Controls.RemoveByKey("MyTree"); instead of this.pDisplayReportName.Controls.Clear();
And, another option would be to add a TreeView in design time (with name tr) rather than dynamically to the panel. Then, use tr.Nodes.Clear(); before tr.BeginUpdate(); and remove following two lines from your code.
TreeView tr = new TreeView();
.
.
.
this.pDisplayReportName.Controls.Add(tr);
Cheers
I've created a directory and file browser TreeView on the left side. I want the users to be able to browse the tree and check the files and directories that they would like to move to another treeview.
The other TreeView is a user control I found online called TreeViewColumn. I will be using that control to allow the user to add other data (categories, attributes) to the files and folders selected.
The trouble I'm running into is two-fold, I need to recursively add all children (I can figure this out) but I need to add unchecked parents to checked children (to preserve the hierarchy).
private void IterateTreeNodes(TreeNode originalNode, TreeNode rootNode)
{
//Take the node passed through and loop through all children
foreach (TreeNode childNode in originalNode.Nodes)
{
// Create a new instance of the node, will need to add it to the recursion as a root item
// AND if checked it needs to get added to the new TreeView.
TreeNode newNode = new TreeNode(childNode.Text);
newNode.Tag = childNode.Tag;
newNode.Name = childNode.Name;
newNode.Checked = childNode.Checked;
if (childNode.Checked)
{
// Now we know this is checked, but what if the parent of this item was NOT checked.
//We need to head back up the tree to find the first parent that exists in the tree and add the hierarchy.
if (tvSelectedItems.TreeView.Nodes.ContainsKey(rootNode.Name)) // Means the parent exist?
{
tvSelectedItems.TreeView.SelectedNode = rootNode;
tvSelectedItems.TreeView.SelectedNode.Nodes.Add(newNode);
}
else
{
AddParents(childNode);
// Find the parent(s) and add them to the tree with their CheckState matching the original node's state
// When all parents have been added, add the current item.
}
}
IterateTreeNodes(childNode, newNode);
}
}
private TreeNode AddParents(TreeNode node)
{
if (node.Parent != null)
{
//tvDirectory.Nodes.Find(node.Name, false);
}
return null;
}
Could anyone help with this code so that it recursively adds checked nodes (and their parent, regardless of checked state). I need to maintain directory hierarchy.
Thanks for any help!
A rather (not-so-clean and not-preferred) solution could be to clone the tree first, and then remove unchecked branches.
Else, when you are adding a node, write a recursive method to traverse through node's parent node until you hit the root. And simply optimize it by checking if childNode.parent already exists, just ignore the branch and move on. i.e. Backtrack to root node.
I got it working. I was already aware of what #Yahya was saying, I was hoping for an easier way / better approach.
The code below is certainly not optimal, I will continue improving it on my end but at this point it is looking through a treeview on the left and copying all of the checked items (and their parents - regardless of CheckedState) to a treeview on the right.
Hopefully this helps someone and thanks for answering #Yahya.
I'm open to improvements but keep in mind this is a one-time use utility.
private void cmdMoveRight_Click(object sender, EventArgs e)
{
tvSelectedItems.TreeView.Nodes.Clear();
// Traverse first level Tree Nodes
foreach (TreeNode originalNode in tvDirectory.Nodes)
{
TreeNode newNode = new TreeNode(originalNode.Text);
newNode.Name = originalNode.Name;
newNode.Tag = originalNode.Tag;
newNode.Checked = originalNode.Checked;
//Only add to the new treeview if the node is checked
if (originalNode.Checked)
{
tvSelectedItems.TreeView.Nodes.Find(originalNode.Parent.Name,true)[0].Nodes.Add(newNode);
}
//Start recursion - this will be called for each first level node - there should technically only be 1 "ROOT" node.
IterateTreeNodes(originalNode, newNode);
}
}
private void IterateTreeNodes(TreeNode originalNode, TreeNode rootNode)
{
//Take the node passed through and loop through all children
foreach (TreeNode childNode in originalNode.Nodes)
{
// Create a new instance of the node, will need to add it to the recursion as a root item
// AND if checked it needs to get added to the new TreeView.
TreeNode newNode = new TreeNode(childNode.Text);
newNode.Tag = childNode.Tag;
newNode.Name = childNode.Name;
newNode.Checked = childNode.Checked;
if (childNode.Checked)
{
// Now we know this is checked, but what if the parent of this item was NOT checked.
//We need to head back up the tree to find the first parent that exists in the tree and add the hierarchy.
TreeNode[] nodestest = tvSelectedItems.TreeView.Nodes.Find(childNode.Parent.Name, true);
if (nodestest.Length > 0)
{
tvSelectedItems.TreeView.Nodes.Find(childNode.Parent.Name,true)[0].Nodes.Add(newNode);
}
else
{
AddParents(childNode);// Find the parent(s) and add them to the tree with their CheckState matching the original node's state
}
}
//recurse
IterateTreeNodes(childNode, newNode);
}
}
private void AddParents(TreeNode node)
{
if (node.Parent != null)// Check if parent is null (would mean we're looking at the root item
{
TreeNode[] nodestest = tvSelectedItems.TreeView.Nodes.Find(node.Parent.Name, true);
if (nodestest.Length > 0)
{
TreeNode[] nodes = tvDirectory.Nodes.Find(node.Name, true);
TreeNode newNode = new TreeNode(nodes[0].Text);
newNode.Name = nodes[0].Name;
newNode.Tag = nodes[0].Tag;
newNode.Checked = nodes[0].Checked;
tvSelectedItems.TreeView.Nodes[node.Parent.Name].Nodes.Add(newNode);
}
else
{
AddParents(node.Parent);
TreeNode newNode = new TreeNode(node.Text);
newNode.Name = node.Name;
newNode.Tag = node.Tag;
newNode.Checked = node.Checked;
tvSelectedItems.TreeView.Nodes.Find(node.Parent.Name,true)[0].Nodes.Add(newNode);
}
}
else // deal with root node
{
TreeNode rootNode = new TreeNode(node.Text);
rootNode.Name = node.Name;
rootNode.Tag = node.Tag;
rootNode.Checked = node.Checked;
tvSelectedItems.TreeView.Nodes.Add(rootNode);
}
}
I have been working on this for a while, but cannot resolve the issue. I have searched S/O & Google, but no luck. Hoping someone on here can help resolve this.
I am not able to display the child nodes in my TreeView control. The data is being retrieved from a database.
The root node appears fine, but there are not child nodes displayed. How can I get the child nodes to be displayed?
My code is:
private void PopulateTreeNode(DataSet dsList)
{
var treeNode = new TreeNode();
foreach (DataRow dr in dsList.Tables[0].Rows)
{
if (dr["RecordTypeID"].ToString() == "1")
{
TreeNode NewNode = new TreeNode(dr["CustomerName"].ToString(), dr["customerID"].ToString());
treeCustomer.Nodes.Add(NewNode);
}
else if (dr["RecordTypeID"].ToString() == "2")
{
TreeNode pNode = new TreeNode(dr["CustomerName"].ToString(), dr["customerID"].ToString());
pNode.ChildNodes.Add(pNode);
}
else if (dr["RecordTypeID"].ToString() == "3")
{
TreeNode pNode = new TreeNode(dr["CustomerName"].ToString(), dr["customerID"].ToString());
pNode.ChildNodes.Add(pNode);
}
}
treeCustomer.Nodes.Add(treeNode);
treeCustomer.DataBind();
}
You don't need to call treeCustomer.DataBind() if you are manually adding nodes like this. It is probably clearing out your tree.
Have you tried calling treeCustomer.ExpandAll() ?
You may also need to set various properties of the treeview too; regarding displaying expand images etc..
It looks like you're adding pNode to the child nodes of pNode. This means it is never getting added to treeCustomer since only treeNode is being added to treeCustomer. It should probably be added to the child nodes of treeNode, or possibly added as a node of treeNode.
I'm experimenting with a treeview in a little C#/Winforms application. I have programatically assigned an ImageList to the treeview, and all nodes show their icons just fine, but when I click a node, its icon changes (to the very first image in the ImageList). How can I get the icon to remain unchanged?
BTW: The "SelectedImageIndex" is set to "(none)", since I don't really know what to set it to, since the image-index is different for the nodes (i guess?).
UPDATE: Here is the code of the application (I'm using Visual Studio Express 2008):
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
treeView1.BeginUpdate();
treeView1.Nodes.Clear();
treeView1.Nodes.Add("root","Project", 0);
treeView1.Nodes[0].Nodes.Add("Foo", "Foo", 2);
treeView1.Nodes[0].Nodes[0].Nodes.Add("Fizz", "Fizz", 3);
treeView1.Nodes[0].Nodes[0].Nodes.Add("Buzz", "Buzz", 3);
treeView1.Nodes[0].Nodes.Add("Bar", "Bar", 1);
treeView1.Nodes[0].Nodes[1].Nodes.Add("Fizz", "Fizz", 2);
treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("Buzz", "Buzz", 3);
treeView1.EndUpdate();
treeView1.ImageList = imageList1;
}
}
}
Simply set the SelectedImageIndex for each node to the same value as ImageIndex. So, if you're creating your node programatically:
TreeNode node = new TreeNode("My Node");
node.ImageIndex = 1;
node.SelectedImageIndex = 1;
Or you can specify the whole lot in the constructor:
TreeNode node = new TreeNode("My Node", 1, 1);
You can do the same thing using the design time editor if you're adding nodes at design time. You just need to set the SelectedImageIndex at the node level and not at the TreeView level.
Hi You can also use the below code:
TreeNode Node = eventArgs.Node;
Node.SelectedImageKey = Node.ImageKey;
what can be done here is, we can utilize TreeView's HitTest method which gives the node information at a given point. Then with that info we can reset the Image to previous. Setting SelectedImageIndex to ImageIndex .Like so
var selectedNodeInfo = treeView.HitTest(treeView.PointToClient(Cursor.Position));
selectedNodeInfo.Node.SelectedImageIndex = selectedNodeInfo.Node.ImageIndex;
I am trying to dynamically populate a treeview object on a sharepoint webpart. For some reason, the node population is triggered automatically and without user input. Below is a sample of how I set up the tree and webpart.
Any suggestions on how to prevent the automatic populate would be appreciated.
The following is in the createchildcontrols method:
this.Tree = new TreeView();
this.Tree.EnableClientScript = false;
this.Tree.PopulateNodesFromClient = true;
this.Tree.Nodes.Add(this.FetchTreeNode());
this.Tree.TreeNodePopulate += new TreeNodeEventHandler(Tree_TreeNodePopulate);
The handler looks like this:
void Tree_TreeNodePopulate(object sender, TreeNodeEventArgs e)
{
List<MyNode> children = this.FetchChildren(e.Node.Value);
foreach (MyNode child in children)
{
TreeNode node = new TreeNode(child.Name, child.UniqueId, child.IconPath);
node.PopulateOnDemand = true;
node.SelectAction = TreeNodeSelectAction.Expand;
e.Node.ChildNodes.Add(node);
}
}
I've been banging my head on this one for a long time, any suggestions would be appreciated.
So I finally figured this out... for some reason, the default behavior of the treeview was to be expanded, so it would call the treenode populate function right off the bat. I was able to get this to work by calling the treeview.collapseall() method.