|
-
Jul 2nd, 2009, 07:10 AM
#1
Thread Starter
Addicted Member
[RESOLVED] TreeView -- Load nodes with multithreading
I have a treeview control with 3 levels of nodes. Domains, users and folders.
When a node gets expanded, I want to load its children dynamically and simultaneously calculate the size of each child in a separate thread so that it will not freeze the GUI.
Code:
public void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
{
switch (e.Node.Level) //Domain level
{
case 0:
string domin = e.Node.Name;
List<string> userList = getUsers(domain);
foreach (string user in userList)
{
TreeNode temp = new TreeNode();
temp.Name = user
temp.Text = user + " (Calculating size) ";
ThreadContainer1 threadcontainer = new ThreadContainer1(e.Node, domain, user);
Thread thread1 = new Thread(new ThreadStart(threadcontainer.GetUserSize));
thread1.Start();
e.Node.Nodes.Add(temp);
}
break;
case 1: //User level
string domain = e.Node.Parent.Name;
string user = e.Node.Name;
List<string> folderList = getFolders(domain, user);
foreach (string folder in folders)
{
TreeNode temp = new TreeNode();
temp.Name = folder;
temp.Text = user + " (Calculating size) ";
ThreadContainer2 threadcontainer = new ThreadContainer2(e.Node, domain, user, folder);
Thread thread1 = new Thread(new ThreadStart(threadcontainer.GetUFolderSize));
thread1.Start();
e.Node.Nodes.Add(temp);
}
break;
}
}
Each thread is supposed to update the referenced node to display the corresponding size after calculating for a while.
However "Cross-thread operation not valid with threading" exception gets thrown whenever a thread tries to access the referenced node.
I googled the issue and found out about delegate.
http://www.shabdar.org/cross-thread-...not-valid.html
But the problem is that node is not a control. So it does not have Invoke() method.
Anyone knows how to solve this problem?
Last edited by winterslam; Jul 2nd, 2009 at 11:56 PM.
-
Jul 2nd, 2009, 07:52 AM
#2
Re: TreeView -- Load nodes with multithreading
The TreeView is a control. It has an Invoke method.
-
Jul 2nd, 2009, 08:00 AM
#3
Thread Starter
Addicted Member
Re: TreeView -- Load nodes with multithreading
 Originally Posted by jmcilhinney
The TreeView is a control. It has an Invoke method.
But I'm passing node, which i not a control, to the thread container.
Should I pass the reference of the TreeView control itself to the thread container? But it gets ugly since the thread is not aware of which 'node' to update unless some positional information about the node is passed too.
-
Jul 2nd, 2009, 08:06 AM
#4
Re: TreeView -- Load nodes with multithreading
Just call Invoke on the TreeView and pass whatever you want. It really doesn't matter what you call Invoke on. That's just a way to cross the thread boundary. Just as long as the control you call it on was created on the right thread it doesn't matter. You can call Invoke on the form if you want, or the TreeView, or even some CheckBox that you don't even use. It doesn't matter.
-
Jul 2nd, 2009, 09:35 AM
#5
Thread Starter
Addicted Member
Re: TreeView -- Load nodes with multithreading
Sorry I don't get what you mean
Mine is similar to this
http://msdn.microsoft.com/en-us/library/a1hetckb.aspx
The only difference is that I'm trying to update nodes of a treeview from separate threads. I'm passing referenced nodes to the respective threads.
-
Jul 2nd, 2009, 09:53 AM
#6
Re: TreeView -- Load nodes with multithreading
You are trying to complicate something that isn't complicated. Just call Invoke on the TreeView. That's it.
-
Jul 2nd, 2009, 06:19 PM
#7
Re: TreeView -- Load nodes with multithreading
Sorry about my previous post. It was after midnight here and I was watching TV, but I should have either taken the time to post properly or not posted at all. I got the impression that you actually knew what to do but you were just baulking at doing it. Regardless, here's what I should have posted:
1. Create a new WinForms project.
2. Add a Button and a TreeView.
3. Add the following code:
Code:
private void Form1_Load(object sender, EventArgs e)
{
this.button1.Click += new EventHandler(button1_Click);
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(CreateNodes);
t.Start();
}
private void CreateNodes()
{
TreeNode[] nodes = {
new TreeNode("Node1"),
new TreeNode("Node2"),
new TreeNode("Node3")
};
nodes[0].Nodes.AddRange(new TreeNode[]
{
new TreeNode("Node1.1"),
new TreeNode("Node1.2"),
new TreeNode("Node1.3")
});
this.AddNodes(nodes);
}
private delegate void AddNodesCallback(TreeNode[] nodes);
private void AddNodes(TreeNode[] nodes)
{
if (this.treeView1.InvokeRequired)
{
this.treeView1.Invoke(new AddNodesCallback(AddNodes), (object) nodes);
}
else
{
this.treeView1.Nodes.AddRange(nodes);
}
}
4. Run the project.
5. Click the Button.
As you can see, the TreeView is updated successfully. Now, as I said, it really doesn't matter which control you call Invoke on as long as it was created on the right thread. Invoke is only a way to cross the thread boundary. It has no bearing on what you can do when you get there. You could change that code to this:
Code:
private void AddNodes(TreeNode[] nodes)
{
if (this.InvokeRequired)
{
this.Invoke(new AddNodesCallback(AddNodes), (object) nodes);
}
else
{
this.treeView1.Nodes.AddRange(nodes);
}
}
or even this:
Code:
private void AddNodes(TreeNode[] nodes)
{
if (this.button1.InvokeRequired)
{
this.button1.Invoke(new AddNodesCallback(AddNodes), (object) nodes);
}
else
{
this.treeView1.Nodes.AddRange(nodes);
}
}
and it will still work because the forrm and all its controls are all owned by the same thread.
For more information on how and why I arrived at this code, read this.
-
Jul 2nd, 2009, 08:38 PM
#8
Thread Starter
Addicted Member
Re: TreeView -- Load nodes with multithreading
Thanks
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|