 |
 |

07-02-2008, 12:22 PM
|
|
Centurion
|
|
Join Date: Aug 2005
Posts: 143
|
|
Flashing ListView Problem
|
|
Thanks to this forum, I made an example using the BakgroundWorker component to calculate the wages of a great number of employees (random database) and display the result in a ListView (one row is added every time there is a progress; the e.UserState is a DataRow in my case). Everything IS ok; all UI controls are responsive and they are updated accordingly. I have no questions about this. Screenshot.
The problem I'm facing is that the ListView flashes when a row is added. The speed at which rows are being added makes the rows almost white! One can hardly read them.
Is there a solution?
YOURS,
|
|

07-02-2008, 02:36 PM
|
 |
Ultimate Contributor
Forum Leader * Guru *
|
|
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
|
|
The problem is in how the ListView control probably works. When the control is painted, each item has to be redrawn. Adding an item causes the control to be repainted. It all gets worse if your columns are sorted; every time an item is added the entire list has to be sorted. Since it looks like you have several hundred items, I'd be willing to bet there's not a whole lot you can do about the flicker, but you can try callling the listview's BeginUpdate method before adding the item and EndUpdate after adding it; this makes sure that the control is only painted after the item is added.
You might want to consider paging the data; you could store information about each employee in a class and keep a list of the information in memory, but only show 100 or so at a time in the ListView. This would make navigation bit less straightforward, but you wouldn't have a severe flicker.
Another alternative involves a special feature of the ListView called virtual mode; when the control is in virtual mode, instead of storing an entire list of items, it only stores the items that are currently displayed. This dramatically reduces flicker (I think). I've never fooled with this but always meant to, so I might try it out and come back with an example if it works out.
|
|

07-02-2008, 03:35 PM
|
|
Centurion
|
|
Join Date: Aug 2005
Posts: 143
|
|
|
|
Thank you so much, AtmaWeapon, for helping me.
Quote:
|
you can try callling the listview's BeginUpdate method before adding the item and EndUpdate after adding it
|
I tried this and it improved just a little.
Quote:
|
You might want to consider paging the data
|
I didn't try this; instead, I reduced the counter in the For ... Next statement to process only 50 items (also tried 100 and 20). It began to flicker annoyingly when the vertical scroll appeared.
I also tried slowing down the speed of adding items by using the Thread.Sleep method. It gave me the time to read items, but no one would consider this a better solution.
Quote:
|
Another alternative involves a special feature of the ListView called virtual mode
|
I am going to do a web research on ListView's Virtual Mode. I do not know why I have a strong believe that this is the best alternative.
My thanks are to you, AtmaWeapon.
YOURS,
|
|

07-02-2008, 03:58 PM
|
 |
Ultimate Contributor
Forum Leader * Guru *
|
|
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
|
|
Being a big dummy like I am, I had a beautiful post typed up in a text editor, then closed it without thinking. This is shorter, but probably better for doing so.
When a LV is in virtual mode (its VirtualMode property is true), it expects you to handle the RetrieveVirtualItem event and provide an item for each item it wants to display. It relies on you to keep the VirtualListSize property up-to-date; it will only ask for items with index 0 - VirtualListSize - 1. The neat part here is you can add a ton of data to the virtual list, then change VirtualListSize to perform the update all at once.
The operation of both forms in the example project is simple: the background worker generates a list of 1000 employees, with an increasing delay between each employee; my goal was to demonstrate that slower updates are required when the list gets bigger but ultimately any pause that demonstrated this made it take way too long to finish. Anyway, the normal form adds items directly to the list view, and it flickers like crazy. The virtual form adds items to a list and periodically updates the list view; it still flickers, but now it's once every second or so.
It seems there's no way around the fact that adding an item introduces flicker. Originally, in VirtualForm I had the BackgroundWorker update VirtualListSize on every item; the result was identical to the normal method. Now, it updates every 100 items, and one last time when all items are generated. The flicker is minimized now. It'd be nice to find a way to get completely around it, but it looks like the ListView wasn't designed to have lots of insertions done at once.
The way my virtualized LV works is similar to if you queued up 100 items and added them via AddRange; I like the virtual mode better because it just seems more elegant.
NOTE: Ignore BaseUiForm; initially I was going to use Visual Inheritance so I only had to design the UI once. For some reason, it didn't work out, and it was easier to just do things the old-fashioned way than figure out what was wrong. I forgot to delete it and only noticed after I'd hand-converted the VS 2008 project to VS 2005 and made the .zip file.
|
|

07-02-2008, 04:10 PM
|
|
Centurion
|
|
Join Date: Aug 2005
Posts: 143
|
|
I am really grateful to you. Now, I'm going to study it and I will certainly come back.
YOURS,
|
|

07-02-2008, 07:15 PM
|
|
Centurion
|
|
Join Date: Aug 2005
Posts: 143
|
|
Dear AtmaWeapon,
This was a very beautiful, complete example you gave me. I really want to thank you very much. I've totally enjoyed studying your code. Your way of coding was so unfamiliar to me that your project was completely new to me: Layout, List, OO thinking which dominated the approach, logic … and what else.. the speed at which you produced the two demos!
I actually studied it carefully, and then closed it and started a new project, and could write a similar one. And although I did, two parts were not clear enough to me:
- How can the execution reach the RetrieveVirtualItem event? I cannot see anything that raises it? Is it raised when the VirtualListSize is changed?
- When the List.Count is a 100-multiple for the first time, the items 1 to 100 are added to the ListView. How about when the List.Count is a 100-multiple for the second time, what is added to the ListView at this turn? Is it 0 to 200, or just 101 to 200? I already understood the function of VirtualListSize from your post.
Quote:
|
I had a beautiful post typed up in a text editor, then closed it without thinking
|
I feel sorry for that, yet I find this one very helpful.
Quote:
|
It'd be nice to find a way to get completely around it, but it looks like the ListView wasn't designed to have lots of insertions done at once.
|
For me, the virtual mode is acceptable.
Quote:
|
I forgot to delete it and only noticed after I'd hand-converted the VS 2008 project to VS 2005 and made the .zip file.
|
I really appreciate this.
YOURS,
|
Last edited by Adel99; 07-02-2008 at 07:24 PM.
|

07-02-2008, 09:13 PM
|
 |
Ultimate Contributor
Forum Leader * Guru *
|
|
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
|
|
Quote:
|
How can the execution reach the RetrieveVirtualItem event? I cannot see anything that raises it? Is it raised when the VirtualListSize is changed?
|
The event is raised internally by the ListView when it feels like it needs to raise the event. I have no idea what triggers this because I didn't have time to experiment. I know that updating VirtualListSize seems to do it, but I'm not sure what else triggers it. If it's truly virtualizing its contents, scrolling would raise this event. Ultimately it's not important; the control knows when it needs to raise the event and it will do so.
Since it still flickers, I believe it's not true virtual behavior; for example, in WPF, when a control is virtualizing its data it will not ask for data items outside of the visible range. The flicker of the Windows Forms ListView seems to suggest it still tries to render all items. I suppose in this version virtual mode is more of a convenience than a performance help.
Quote:
|
When the List.Count is a 100-multiple for the first time, the items 1 to 100 are added to the ListView. How about when the List.Count is a 100-multiple for the second time, what is added to the ListView at this turn? Is it 0 to 200, or just 101 to 200? I already understood the function of VirtualListSize from your post.
|
This is related to my confusion above. Let's say the control displays 30 lines. If the control fully virtualizes its content, then it will ask for 0-29, and not ask for anything else until it is scrolled. Since the control flickers, it looks like it at least asks for 101 to 100 the second time, but it could be 0 to 200. If you put some Debug.WriteLine statements into the handler, I'm sure you could determine this.
|
|

07-03-2008, 04:42 AM
|
|
Centurion
|
|
Join Date: Aug 2005
Posts: 143
|
|
Thanks AtmaWeapon.
That was very helpful.
Thanks again.
YOURS,
|
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
| |
|
|
|
 |
|