|
Thanks, but I already tried that and it actually added to the time as the function returns a single treenode but with a nodes.count property of 5000.
|
|
|
|
|
Were you calling it inside of a loop? You should really only call them once, right before you add the first node and after you have added the last one, not each time you add the node.
|
|
|
|
|
No, the function is only called once and returns the MainNode then just one TreeView1.Nodes.Add(MainNode);
Because MainNode already has child nodes it's all that is required - all the looping goes on when parsing the xml and this successfully creates the mainnode with all the children in less than 0.1 sec.
|
|
|
|
|
Depending on how you are actually building up the nodes, collect them in a List<TreeNode> collection first. Once you are done creating them, call AddRange instead of Add and pass in the list (you will need to call List.ToArray() to pass it in as AddRange only accepts arrays).
Using AddRange is considerably faster than calling Add repeatedly, especially for large amounts of adds.
As Dave mentioned, you should also call BeginUpdate and EndUpdate as well as SuspendLayout , ResumeLayout to prevent the UI from repainting after each add. (I don't think BeginUpdate , EndUpdate implicitly make the calls to SuspendLayout , ResumeLayout , but if they do you wouldn't need to call both explicitly.)
[modification at 17:01 Thursday 20th September, 2007]
The SuspendLayout , ResumeLayout calls won't actually buy you anything in this case. The BeginUpdate , EndUpdate are the ones you want to use.
[/modification]
|
|
|
|
|
Good answer. It's surprising how many people aren't aware of the performance benefits of AddRange.
Deja View - the feeling that you've seen this post before.
|
|
|
|
|
Pete O`Hanlon wrote: Good answer. It's surprising how many people aren't aware of the performance benefits of AddRange.
Thanks. In some ways it's surprising, but I don't think it's clearly documented that AddRange has better performance for certain situations.
|
|
|
|
|
I'll certainly bear that in mind for other situations. I just tried it, and although it didn't help in this case, there was no extra overhead in terms of time and is potentially far more flexible.
|
|
|
|
|
Created a quick example code to see if this helps define my problem
class Tree
{
public static TreeNode Build()
{
TreeNode MainNode = new TreeNode("MainNode");
for (int i = 0; i <= 5000; i++)
{
TreeNode ChildNode = new TreeNode("ChildNode" + i.ToString());
TreeNode SubNode = new TreeNode("SubNode");
ChildNode.Nodes.Add(SubNode);
MainNode.Nodes.Add(ChildNode);
}
return MainNode;
}
}
private void Form1_Load(object sender, EventArgs e)
{
TreeNode MainNode = Tree.Build();
treeView1.Nodes.Add(MainNode);
}
|
|
|
|
|
Yes, the code sample helped clarify things. I would change the Build function so that it takes a reference to the TreeView and also makes use of the AddRange call to add the nodes. It would end up looking something like this:
public static void Build(ref TreeView treeView)
{
TreeNode mainNode = new TreeNode("MainNode");
List<TreeNode> childNodes = new List<TreeNode>();
for (int i = 0; i <= 5000; i++)
{
TreeNode childNode = new TreeNode("ChildNode" + i.ToString());
TreeNode subNode = new TreeNode("SubNode");
childNode.Nodes.Add(subNode);
childNodes.Add(childNode);
}
treeView.Nodes.AddRange(childNodes.ToArray());
} Depending on how you are actually creating the sub nodes, you may also want to do something similar and use a List<TreeNode> and AddRange to populate the Nodes collection of the childNode object.
This should give you better performance.
|
|
|
|
|
Thanks for your efforts Scott. Unfortunately, it actually adds 600ms in the simple example I used.
Created this below, a form with 2 treeviews a listbox and a button.
I think it's just the .net treeview control is just slow period! Unfortunately it's the only control that will suffice in the real application unless anyone knows a better (possibly free?) one.
Thanks for everyones time anyway.
public static TreeNode Build()
{
TreeNode mainNode = new TreeNode("MainNode");
for (int i = 0; i <= 5000; i++)
{
TreeNode childNode = new TreeNode("ChildNode" + i.ToString());
TreeNode subNode = new TreeNode("SubNode");
childNode.Nodes.Add(subNode);
mainNode.Nodes.Add(childNode);
}
return mainNode;
}
public static void Build(ref TreeView treeView)
{
TreeNode mainNode = new TreeNode("MainNode");
List<TreeNode> childNodes = new List<TreeNode>();
for (int i = 0; i <= 5000; i++)
{
TreeNode childNode = new TreeNode("ChildNode" + i.ToString());
TreeNode subNode = new TreeNode("SubNode");
childNode.Nodes.Add(subNode);
childNodes.Add(childNode);
}
treeView.Nodes.Add(mainNode);
treeView.Nodes[0].Nodes.AddRange(childNodes.ToArray());
}
private void button1_Click(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
treeView2.Nodes.Clear();
listBox1.Items.Clear();
DateTime dtBuild1Start;
DateTime dtBuild1End;
TimeSpan tsBuild1;
DateTime dtBuild2Start;
DateTime dtBuild2End;
TimeSpan tsBuild2;
Application.DoEvents();
dtBuild1Start = DateTime.Now;
TreeNode MainNode = Build();
treeView1.Nodes.Add(MainNode);
dtBuild1End = DateTime.Now;
tsBuild1 = dtBuild1End - dtBuild1Start;
listBox1.Items.Add("Build1 in " + tsBuild1.TotalMilliseconds.ToString() + " milliseconds");
dtBuild2Start = DateTime.Now;
Build(ref treeView2);
dtBuild2End = DateTime.Now;
tsBuild2 = dtBuild2End - dtBuild2Start;
listBox1.Items.Add("Build2 in " + tsBuild2.TotalMilliseconds.ToString() + " milliseconds");
}
|
|
|
|
|
Hmmm...I actually just ran your sample application and your way took 409 ms while mine took 676 ms. That result bothers me for a couple of reasons:
- The times are very different. Granted, that is probably due to hardware differences, but I wouldn't have thought it would be that significant.
- The use of
AddRange should still be faster.
I made one tweak to your sample, which changed the times to be within ~30 ms of each other. After several runs, it was inconclusive as to which method was consistently faster.
The change I made was in the Build(ref TreeView) function and changed the following lines:
treeView.Nodes.Add(mainNode);
treeView.Nodes[0].Nodes.AddRange(childNodes.ToArray()); to
mainNode.Nodes.AddRange(childNodes.ToArray());
treeView.Nodes.Add(mainNode);
|
|
|
|
|
Anyway - I've had a bit of a play round earlier on today. The best way for you to do this would be to use a BackgroundWorker component. What you need to do is start filling the tree on another thread. The key to this is to get the data into the treeview in manageable chunks and load them in, in about 100 node chunks.
Deja View - the feeling that you've seen this post before.
|
|
|
|
|
|
Glad you found a control that seems like it will work for you. I'm still puzzled over the large difference in times between the same test on my system and yours...
|
|
|
|
|
I'm testing this at work on a garbage PC with loads of memory hogging junk that *has* to be on here. I'll retest at home tonight on a decent machine.
The control I found has promise but needs a lot of work before I could use it in a production environment which I don't have time for right now. Thought I'd mention it anyway as the performance it provides is outstanding.
Dsve
|
|
|
|
|
The big difference was the PC. At home I'm acheiving around 250ms!
I've ammended the code as you suggested and I'm seeing similar results - using the List<> is approximately the same as not. There's occaisionally a slight difference of 30ms or so, as you found, which can go to either method but on average yours is the quicker.
I've tried it with a real world sample reading 15000 childNodes (so 30001 actual TreeNodes) from an xml file on a seperate thread and returning an object to the UI that holds the List<>, the start time and a result of the xml read operation - the UI is then updated from the List in the method you suggested and the whole thing is now completing in about 1.5 seconds.
That is quite remarkable and definately acceptable so problem solved
Many thanks once again,
Dave
|
|
|
|
|
Glad to know the speed differences were due to hardware. Those are the same results I saw, on average the solution using AddRange being faster the majority of the time.
It's good to hear that using a real sample you were able to achieve the results you wanted.
Glad to have helped.
|
|
|
|
|
I developed a treeview using backgroundworker.
My Tree have aprox. 2100 nodes, aprox. 8000 subnodes and sub-subnodes ... the rest to aprox 100.000.
Using a thread you can make the gui immediately responsive, because, usualy, you can't show more than aprox. 50 main nodes in one page.
Before using that,it took aprox 3-5 seconds (on my machine) to load.
Now is apparently instantly ... and that satisfied my needs .
So, Guys use backgroundworker to realy speed-up that f***ing Treeview from .NET.
Share knowledge !
|
|
|
|
|
dsGrid is the dataSet of gridview data.
DataTable tbl = dsGrid.Tables[0];
tbl.Rows[e.RowIndex][i].Controls[3];
When I use this, there is an error:
'object' does not contain a definition for 'Controls'. Am I missing out some reference?
Please help me on this.
Thanks
|
|
|
|
|
ss.mmm wrote: 'object' does not contain a definition for 'Controls'. Am I missing out some reference?
Nope. The DataTable Rows collections returns a DataRow object. A DataRow object does NOT have a Controls collection. The only collection a DataRow exposes is an Item array which contains the objects for each column in that row. Any data in a column is return as a System.Object. If you want to use the object in that column you have to cast it back to the original type, giving you the ability to use the object again.
|
|
|
|
|
Thanks for the information.
Thanks,
|
|
|
|
|
And don't cross post in multiple forums. It's rude and makes it very difficult for multiple people to collaborate on a solution.
|
|
|
|
|
hi ,
im currently working on a project (C#) that demends to have a minimal support of updating the current currency rates and give a minimal ability to convert from diferent curency for example
the dolar today worth 4.13 israel new shekel conversion was USD -> ILS
so i thought to my self theres probably tons of free web services which support that kind of action , but after i was googling and searching thecodeproject i found that there are only a few webservices for that matter that are free and all the servers that i have found which support these web services seems to be down ex: http://www.xmethods.com , also i found some articles in thecodeproject which present nice solutions for this problem
but none of them had currency rates for Israeli new shekel which is the main currency i need to work with or they were too complex for such a small thing
(a solution that involves registering to a daily email list of a certain site
which provide you updated currency rates , then use POP3 track the email , analize its content.....)
so im asking for your advice, which technique should i use to get updated currency rates into my program? is there any code out there for that?
are there any reliable servers that support these webservices free that you know of?
any other information regard this problem is more than welcome!
thanks
Net
|
|
|
|
|
udikantz wrote: is there any code out there for that?
Absolutely! See this[^] article.
/ravi
|
|
|
|
|
thanks for the article ,
i will play with your source and samples.
although i was thinking about something that is more specific about currencies cause i realy didnt want to spend time on coding convertors and ect....
but looks like i'll have to do something about it :P
so thanks man
"'1=1--
|
|
|
|