Updating the UI from events generated by a background thread

My WPF app runs long functions on background threads, usually with a button / command click, eg.

StartCommand = new RelayCommand(async o => await StartAsync(), o => true);

...

private async Task StartAsync()
{
    await Task.Run(() => LongRunningFunction());
}

      

These long running functions raise various events to report progress to the user, update UI values, etc. The view model handles such events and updates related properties, for example:

private void LongRunningProcessProgressChanged(object sender, ProgressEventArgs e)
{
    StatusMessageText = string.Format("Progress {0}%", e.Progress);
}

      

Most of the time this works fine, but sometimes I get the usual UI update exception from the background thread ("the calling thread cannot access this object because another thread owns it"), so I need to wrap the code in Dispatcher.Invoke(...)

. I haven't really noticed what it is when I do this or not, so can anyone shed some light on it?

To be honest, I'm surprised the above code works at all. The breakpoint confirms that these event handlers are fired on the worker thread and not on the UI thread, so why am I not seeing the exception all the time? Is it related to the property type being updated?

Edit People are suggesting answers to a problem I already know about. By repeating my question, I may have confused readers with the "Most of the time this works fine, but sometimes I get the usual exception." I didn't mean that this is an intermittent problem - I did mean that some of my VMs have no problem updating bound properties in their respective progress handler, while other VMs do. I suspect it has something to do with the type of the property, for example. updating the string property works, but not the ObservableCollection.

My question was more of a curiosity, i.e. why some related properties are ok with updating from b / g stream and others not.

+3


source to share


2 answers


Your code should always throw exceptions when updating the UI from background threads. You don't always see exceptions because exceptions happen on a background thread and remain unobserved . For such exceptions

.. The TPL should block these exceptions and hold them until they are thrown again when the consumer code accesses the task.

So you just don't see the exceptions immediately after you have picked them from the background task.

<h / "> Update



This answer sheds light on common scenarios when accessing a control from another thread. About the problem you described, it actually depends on the type of property you are binding to, as pointed out on the MSDN forum :

Data binding with primitive types is mostly type-safe, as the binding mechanism internally uses the dispatcher to return to the UI thread for you.

However, you need to take care of the collections. For example, ObservableCollection won't handle this, so you need to make changes to the collection on the UI thread.

In this report, the blog you can find more information.

+2


source


The problem you are having is that you are trying to update a UI element that is on a different thread and you can try this



 App.Current.Dispatcher.Invoke(new Action(() =>
            {
               // your code
            }));

      

-1


source







All Articles