Good Morning Guys-
I'm just learning C# so please bare with me! I have a winlistview on a tab page that I am populating with a couple hundred (sometimes more) entries. I populate this winlistview when the form loads. Since it takes a bit to search the files and populate that listview, I decided to start a thread to do the work in the background, so the user can watch as the new entries appear.
It doesn't work right. I get "random" errors from the winlistview as it is being populated. Now there are two listviews that are being updated on the main page and its completely random as to which one throws an error and causes the program to crash. The errors also are random. On one launch it complains about one thing, on another launch it'll throw an exception about something else. I am thinking that I am not doing something properly with the threading.
I'm wondering if anyone could point me in the right direction as to what I need to do in order to fire off another thread and have these winlistviews updated "in the background" as the end user watches.
Here's what I've tried (with no success)
On the On Load event, creating a new thread and myThread.Start()'ing that thread. This usually really upsets the apple cart, even the ultralabels will throw errors. So I read that you cannot update the UI from threads, you have to use delegates.
So what I've done is on the load event, create a new thread, call that thread. The thread gets called, and it creates a delegate with the method that populates the winlistview, like this:
SimpleDelegate myDelegate = new SimpleDelegate(PopulateListView);
myDelegate();
That does not seem to work for the winlistview either (but the labels now never throw errors). If I use this procedure for a windows listview control, it works fine and updates and never crashes.
So long story short is could someone point me in the right direction for adding items to an ultra winlistview from another thread while the main application is still doing its thing accepting user input and whatnot?
Thanks!!
************** Exception Text **************System.NullReferenceException: Object reference not set to an instance of an object. at Infragistics.Win.UIElement.VerifyChildElements(ControlUIElementBase controlElement, Boolean recursive)
The short answer is: never update any Windows Forms control on a thread other than its owning thread. The kinds of exceptions you've described - especially their "random" nature - are typical of issues caused by unsafe threading. All Windows Forms controls are not thread-safe, including ours.
This doesn't mean that you can't use threading. While you must make changes to the UI on the main thread, you can possibly do other activities on a background thread, which you would then be able to use on the main thread. For example, you might build your list on a background thread, without that list being bound to WinListView. When your thread is complete, you can pass that list back to the main thread, and from there bind it to the control.
I find the following article on MSDN to be a good resource for learning about the risks of threading in Windows Forms, and the variety of ways to use multiple threads safely:Safe, Simple Multithreading in Windows Forms
Ok so I read the article and I've modified my code (I'll paste it below). The second thread fires off that scans the disk for files and it calls a delegate to update the winlistview if invokerequired is true (which it always is). It works awesome for the most part with one exception. If I resize the window while it is scanning, it crashes. (Not every time, but most of the time). The thing that stinks is that when this crash occurs, there is no debug information. I even start the app in debug mode and the crash happens it just says it stopped working and that's it, there's nothing to debug (yes i have debug mode profile going and am compiling the code w/ debugging information). It only does this when I resize the window.
The Code looks like this:
if
(ultraListViewInvalidMP3s.InvokeRequired)
{
(UpdateUltraListViewInvalidMP3s);
[] { MP3File });
}
else
UpdateUltraListViewInvalidMP3s(MP3File);
delegate
MP3File);
private
void UpdateUltraListViewInvalidMP3s(MP3FileStruct MP3File)
ultraListViewInvalidMP3s.Items.Add(
null, MP3File.sArtist);
If I comment out the "Items.Add", the program will never crash. But with that in there it crashes. Sometimes it even crashes when another window pops up on top of my application (ie, someone IMs me on Yahoo and it pops up in the middle of the screen, wham, my application crashes). So it almost looks like the painting or drawing is causing the crash.
I'm not sure what I am doing wrong that is causing this. For ha-ha's I brought in a plain windows listview and used the delegates on it, and I'm not having the problem. It's probably "luck of the draw" why sometimes it crashes and sometimes it doesn't, but is there anything you can see right off the bat that I am doing improperly?
Thanks a bunch in advance!
shultas said:It's probably "luck of the draw" why sometimes it crashes and sometimes it doesn't...
Consider replacing "this.Invoke(...)" with "this.BeginInvoke(...)". As mentioned in the first part of the article, this prevents holding up your worker thread, since you're not getting back a return value from your UpdateUltraListViewInvalidMP3s() method.
I'm uncertain whether this is the cause of the behavior you're seeing. Even if this isn't the cause, it should make your code somewhat more performant.
Please let us know whether this helps.