views:

389

answers:

2

Hello,

I'm trying to create a custom, in-house application that is going to access other internal systems which broadcast their names and IP addresses via UDP. I'm trying to create a multi-threaded dialog that polls for UDP messages every 500 ms for 15 seconds, parses the UDP messages and then adds the names of the detected systems to a ListBox in the dialog, updating it in real time. I've already got the UDP scanning code tested and done, the only problem is updating the ListBox across threads. Any time I try to access the ListBox's Items or ItemSource properties, I get a System.InvalidOperationException : "The calling thread cannot access this object because a different thread owns it."

The relevant stack trace portion:

   at System.Windows.Threading.Dispatcher.VerifyAccess()
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Controls.ItemsControl.set_ItemsSource(IEnumerable value)

This occurs regardless of whether I'm using an ObservableCollection (I know, has nothing to do with the collection type), a HashSet or any other object. Can anybody help me with accessing the GUI across different threads ?

+4  A: 

You can't access the gui safely from other threads. All calls have to be dispatched via a call to Invoke to be executed on the main thread. This is a legacy hang-up that Windows has been saddled with for years.

Here's a snippet of code that should get you started... (found here: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/360540eb-d756-4434-86f9-a3449f05eb55/ )

if(textbox.Dispatcher.CheckAccess())
{
   // The calling thread owns the dispatcher, and hence the UI element
   textbox.AppendText(...);
}
else
{
   // Invokation required
   textbox.Dispatcher.Invoke(DispatcherPriority.Normal, [delegate goes here]);
}

There is additional clarification here: http://channel9.msdn.com/forums/TechOff/251835-WPF-Invoke-and-Anonymous-delegates/

Andrew Rollings
Wow, that was an amazingly useful answer, and it did the trick. Thank you so much. I'd up-vote your answer a dozen more times if I could.
Alex Marshall
Also note you can dispatch back to the UI thread asynchronously as well using the Dispatcher.BeginInvoke / EndInvoke pattern
Foovanadil
+2  A: 

As Andrew already said, you should synchronize the access to GUI across the threads (it's just the way it is - you can't do much about it).

However, Dispatcher is a WPF-specific synchronization mechanism. If you'd like to stick to a more general approach, then take a look at System.Threading.SynchronizationContext class.

archimed7592