Threading issues when updating GUI
-
Hello, First of all, I do realise that the following description is incomplete and it is probably impossible to deduce the exact causes of the problem from it -- the code I'm working on is simply too long to post here in full. I would, however, be very grateful for any hints on how to debug it, or pointers to useful resources on the subject. Here's what I'm struggling with: I'm working on an RSS aggregator in C#. As the network functions are blocking, I use a separate thread for updating the feed subscriptions. The update function generates events which are then caught by each notification 'subsystem' (popup notifiers, tray icon and context menu for now). Realising that UI controls have to be updated from the thread they were created in, I added appropriate InvokeRequired clauses everywhere an event cause the UI to update -- as described in MSDN help. The manual suggests that this should solve the problem but despite that the program crashes frequently. I get the following exception:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
The error occurs when I click on the tray icon just after the feeds have been updated, presumably when the events are still propagating (new items are individually added to the context menu, in the tests I'm using there can be up to about 150 of them). I also looked through a more extensive guide on the subject of threads in general 'Multi-threading in .NET: Introduction and suggestions' (http://www.yoda.arachsys.com/csharp/threads/) but nothing useful came up. Here's an example of event handler (taken from the tray icon context menu class):private delegate void subscriptions_FeedsUpdatedCallback(object sender, FeedsUpdatedArgs e); void subscriptions_FeedsUpdated(object sender, FeedsUpdatedArgs e) { if (this.InvokeRequired) { var d = new subscriptions_FeedsUpdatedCallback(subscriptions_FeedsUpdated); this.BeginInvoke(d, new object[] { sender, e }); } else { HideInfoItem(); // hide the menu entry which displays status information ('Updating...' / 'Connection error') foreach (var menu in FeedMenus) // show submenus for each RSS feed menu.Visible = true; foreach (Subscription feed in subscriptions.Channels) { ToolStripMenuItem menuItem = (ToolStripMenuItem)(this.Items.Find(feed.Name, false))[0]; foreach (Rss.RssItem newitem in feed.NewItems) menu
-
Hello, First of all, I do realise that the following description is incomplete and it is probably impossible to deduce the exact causes of the problem from it -- the code I'm working on is simply too long to post here in full. I would, however, be very grateful for any hints on how to debug it, or pointers to useful resources on the subject. Here's what I'm struggling with: I'm working on an RSS aggregator in C#. As the network functions are blocking, I use a separate thread for updating the feed subscriptions. The update function generates events which are then caught by each notification 'subsystem' (popup notifiers, tray icon and context menu for now). Realising that UI controls have to be updated from the thread they were created in, I added appropriate InvokeRequired clauses everywhere an event cause the UI to update -- as described in MSDN help. The manual suggests that this should solve the problem but despite that the program crashes frequently. I get the following exception:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
The error occurs when I click on the tray icon just after the feeds have been updated, presumably when the events are still propagating (new items are individually added to the context menu, in the tests I'm using there can be up to about 150 of them). I also looked through a more extensive guide on the subject of threads in general 'Multi-threading in .NET: Introduction and suggestions' (http://www.yoda.arachsys.com/csharp/threads/) but nothing useful came up. Here's an example of event handler (taken from the tray icon context menu class):private delegate void subscriptions_FeedsUpdatedCallback(object sender, FeedsUpdatedArgs e); void subscriptions_FeedsUpdated(object sender, FeedsUpdatedArgs e) { if (this.InvokeRequired) { var d = new subscriptions_FeedsUpdatedCallback(subscriptions_FeedsUpdated); this.BeginInvoke(d, new object[] { sender, e }); } else { HideInfoItem(); // hide the menu entry which displays status information ('Updating...' / 'Connection error') foreach (var menu in FeedMenus) // show submenus for each RSS feed menu.Visible = true; foreach (Subscription feed in subscriptions.Channels) { ToolStripMenuItem menuItem = (ToolStripMenuItem)(this.Items.Find(feed.Name, false))[0]; foreach (Rss.RssItem newitem in feed.NewItems) menu
Jergosh wrote:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
You can actually turn this error off if you want to, but it makes more sense to work around it. The way I do it is to do threading with the BackgroundWorker class, and to use the reportProgress method to fire a message back to the main thread, which then is where I update UI.
Christian Graus Please read this if you don't understand the answer I've given you "also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
-
Hello, First of all, I do realise that the following description is incomplete and it is probably impossible to deduce the exact causes of the problem from it -- the code I'm working on is simply too long to post here in full. I would, however, be very grateful for any hints on how to debug it, or pointers to useful resources on the subject. Here's what I'm struggling with: I'm working on an RSS aggregator in C#. As the network functions are blocking, I use a separate thread for updating the feed subscriptions. The update function generates events which are then caught by each notification 'subsystem' (popup notifiers, tray icon and context menu for now). Realising that UI controls have to be updated from the thread they were created in, I added appropriate InvokeRequired clauses everywhere an event cause the UI to update -- as described in MSDN help. The manual suggests that this should solve the problem but despite that the program crashes frequently. I get the following exception:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
The error occurs when I click on the tray icon just after the feeds have been updated, presumably when the events are still propagating (new items are individually added to the context menu, in the tests I'm using there can be up to about 150 of them). I also looked through a more extensive guide on the subject of threads in general 'Multi-threading in .NET: Introduction and suggestions' (http://www.yoda.arachsys.com/csharp/threads/) but nothing useful came up. Here's an example of event handler (taken from the tray icon context menu class):private delegate void subscriptions_FeedsUpdatedCallback(object sender, FeedsUpdatedArgs e); void subscriptions_FeedsUpdated(object sender, FeedsUpdatedArgs e) { if (this.InvokeRequired) { var d = new subscriptions_FeedsUpdatedCallback(subscriptions_FeedsUpdated); this.BeginInvoke(d, new object[] { sender, e }); } else { HideInfoItem(); // hide the menu entry which displays status information ('Updating...' / 'Connection error') foreach (var menu in FeedMenus) // show submenus for each RSS feed menu.Visible = true; foreach (Subscription feed in subscriptions.Channels) { ToolStripMenuItem menuItem = (ToolStripMenuItem)(this.Items.Find(feed.Name, false))[0]; foreach (Rss.RssItem newitem in feed.NewItems) menu
I've seen the exception thrown when you are calling BeginInvoke on a control that has been instantiated but has not yet become visible. .NET 2.0 apparently creates the backing Win32 handle lazily, when the control is about to become visible for the first time, and if you happen to call Invoke/BeginInvoke before it, it fails with that error. Can you try accessing the
Handle in the constructor of that control? This forces creation of the underlying handle. Regards Senthil [MVP - Visual C#] _____________________________ [My Blog](http://msmvps.com/blogs/Senthil) | [My Articles](http://www.codeproject.com/script/articles/list_articles.asp?userid=492196) | [My Flickr](http://www.flickr.com/photos/senthilkumar/) | [WinMacro](http://geocities.com/win_macro)
-
I've seen the exception thrown when you are calling BeginInvoke on a control that has been instantiated but has not yet become visible. .NET 2.0 apparently creates the backing Win32 handle lazily, when the control is about to become visible for the first time, and if you happen to call Invoke/BeginInvoke before it, it fails with that error. Can you try accessing the
Handle in the constructor of that control? This forces creation of the underlying handle. Regards Senthil [MVP - Visual C#] _____________________________ [My Blog](http://msmvps.com/blogs/Senthil) | [My Articles](http://www.codeproject.com/script/articles/list_articles.asp?userid=492196) | [My Flickr](http://www.flickr.com/photos/senthilkumar/) | [WinMacro](http://geocities.com/win_macro)
S. Senthil Kumar wrote:
I've seen the exception thrown when you are calling BeginInvoke on a control that has been instantiated but has not yet become visible. .NET 2.0 apparently creates the backing Win32 handle lazily, when the control is about to become visible for the first time, and if you happen to call Invoke/BeginInvoke before it, it fails with that error.
This sounds very promising as the controls are indeed hidden -- do you know if this bug applies to .NET 3.5? Cheers, Greg