When optimizing UI in our project I noticed really strange boost up in ListView and didn’t understand where it comes from.
Simple adding 5000 elements to listView (View: List) – 3815 ms:
for (int i = 0; i < 5000; i++)
listView1.Items.Add((Guid.NewGuid().ToString()));
With BeginUpdate() + EndUpdate() – 2317 ms:
listView1.BeginUpdate();
for (int i = 0; i < 5000; i++)
listView1.Items.Add((Guid.NewGuid().ToString()));
listView1.EndUpdate();
With Hide() + Show() – 163ms (NO MISTAKE, over 10 times faster):
listView1.Hide();
for (int i = 0; i < 5000; i++)
listView1.Items.Add((Guid.NewGuid().ToString()));
listView1.Show();
The style also changed. Instead of 2 columns now I have 4.
Why this way is so fast ?
Moreover, why starting with hidden ListView (Visible: false), and showing it after population doesn’t have the same performance boost ?
TreeView is different. Simple adding 5000 nodes – 2130 ms:
for (int i = 0; i < 5000; i++)
treeView1.Nodes.Add((Guid.NewGuid().ToString()));
With Hide() + Show() – 1048 ms:
treeView1.Hide();
for (int i = 0; i < 5000; i++)
treeView1.Nodes.Add((Guid.NewGuid().ToString()));
treeView1.Show();
With BeginUpdate() + EndUpdate() – 291 ms:
treeView1.BeginUpdate();
for (int i = 0; i < 5000; i++)
treeView1.Nodes.Add((Guid.NewGuid().ToString()));
treeView1.EndUpdate();
It seems to be a bug. When the control is hidden, it doesn’t calculate the extents of the items (something like
Graphics.MeasureStringor its native equivalent) when they are added (which makes sense) and doesn’t calculate it later, when the control is shown (which is probably a bug). For this reason you get 4 columns instead of 2. Notice that when you get 2 columns, items are not truncated, because this size calculation was performed. When you get 4 columns, the display is generally incorrect.And why it doesn’t make it with being invisible from the beginning? The reason is, because in this case the handle to the control is not created (underlying Win32 control is not created yet) until you call
Showmethod or make anything what forces the handle to be created. And then,Showwill create the handle for the first time, doing a lot of other code, includingOnHandleCreatedand somewhere at this point the code organizes the items and calculates their sizes.You can check
IsHandleCreatedproperty isfalseuntil the firstShowcall, if the control was invisible from the beginning.You can also create a handle explicitly, ie. by simply trying to read the
Handleproperty (this forces the handle to be created), and then it behaves the same way – is fast, but the display is wrong:If the handle was created earlier, the
OnHandleCreatedalong with size calculation was invoked too, but at the time the list was empty.