Update UI-Element from different thread and different class - wpf

I don't quite understand the Dispatcher. I'm working on a WPF-application.
Following scenario:
I call an asynchronous method from code-behind. (Method is in another module, but public. I can't access UI-elements from there tho.)
Now I want to change a ListBox from that method, but obviously I can't access that UI-element from this method, which makes the Dispatcher kind of useless since I get the error that the UI-element isn't declared.
So I can only call BeginInvoke from the Code-Behind? Doesn't make much sense, no?
The dispatcher code I have in my asynchronous method, outside the mainWindow-class:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, CType(Sub() AddLogFileText(stringLogFile), SendOrPostCallback))

Related

How to deal with cross-thread access exceptions?

A common exception one can get when working with multiple threads in WPF is:
The calling thread cannot access this object because a different thread owns it
What are the options to deal with this properly?
Depending on the situation there are various options:
Accessing a control from another thread
e.g. updating a TextBlock with progress information.
Data Binding:
In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)
There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...
Dispatching:
You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).
e.g.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.
e.g.
void Update()
{
Action action = () => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.
Special cases:
BackgroundWorker
Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)
Timers
In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.
You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.
Accessing an object created on another thread
e.g. loading an image in the background.
If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.
Accessing a data object from another thread
That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.
This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.
That would be several hundred lines of code, for something I "figured out".
But the summary is:
App_OnStartup
generate a background thread
in the callback,
Call
Application.Current.MainWindow.Dispatcher.CheckAccess() - gets the exception
Application.Current.Dispatcher.CheckAccess() does not
I have a udp listener object that communicates through events where the method/callbacks are +='ed in my mainWindow wpf .cs file.
The event handler functions are called with parameters, one being the message I want displayed in a listbox in the mainWindow.cs
Using the information in this thread by H.B. above;
I have added, tested and handled the crossthread in wpf in my eventhandler callback using the following code, but I use a real message not a hard coded one:
listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere")));
UPDATE:
This is better because you can put more things in the anonymous function.
listBox1.Dispatcher.Invoke((Action)delegate
{
listBox1.Items.Add(e.ReaderMessage);
});

Dispatcher madness, how am i still in the background thread or is Visual Studio wrong?

I am invoking a service module call from my viewmodel in the background thread by using a background worker, all fine and dandy.
The service module method has an action parameter which is invoked when the service returns. Now I need to get back to the UI thread at this point to invoke the action (I have also tried getting back to the UI thread in my viewmodel method which is invoked from the service module.)
So to the crux of the matter I have tried
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => code stuff here);
Which produces invalid cross thread access (fine I cant get to rootvisual here I understand)
I then tried to get the Dispatcher a different way as below
Deployment.Current.Dispatcher.BeginInvoke() => code here);
I have also tried a static class which has a Dispatcher property which I set in my application startup method and then try invoke using that.
Whilst using the Deployment dispatcher and my static class's dispatcher do not produce invalid cross thread access, the crux that has me so confused is that if i breakpoint inside the code that is being invoked by these dispatchers then I get this System.Threading.Thread.CurrentThread.ThreadState is Background
I can however update my properties in my view model and the view does indeed update without an issue, but I want to know if there is still something going wrong here and this will be a problem in the future.
To get to the UI dispactcher you can use this code -
Application.Current.Dispatcher.BeginInvoke() => code here);
For your comment -
I should add the most confusing part is from what I've read using a dispatcher is meant to guarantee you get back onto the UI thread!
You have misinterpreted that invoking a delegate on UI dispatcher will take you to UI thread, the above piece of code invocation will only queue the delegate on UI dispatcher and will execute on the UI thread. However, execution point will be there on the background thread from where you are calling this action.
These links might be useful to you - Understanding Dispatcher and Overview of dispatcher

UI update after background operation blocks binding on ObservableCollection

I have this:
Shows a waiting animation to 'block' the UI while performs a loading operation in the background.
At the end of the loading I call a method that instances a User Control and displays some data by using Bindings (and ObservableCollection among others)
This User Control gets displayed and user can interact with it, however the ObservableCollection seems to be stuck in another thread as it doesn't allow to add new items to it.
I've tried to update the UI at the Completed event of a BackgroundWorker, using Dispatcher, using DispatchTimer... all of this displays the User Control, but the ObservableCollection stays of out reach for adding.
The code that tries to add items to the collection is inside the UserControl.
The exact error is: "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"
This does not happen if I don't do the loading in the background.
Thank you for any workaround for this.
By the way, trying to add the items using Dispatcher doesn't work either.
In other words, what I would like to do is to create an object in the UI Thread while being in the background... I know this may sounds silly.
You may have to check which Dispatcher you are using? In your case you could be referring to two different dispatchers.
Also why not use thread safe observable collection?
Usually I will create the objects on my UI thread, then populate them with data obtained from a background thread.
For example,
void async LoadButton_Clicked(object sender, EventArgs e)
{
MyCollection = new ObservableCollection<SomeItem>();
// Can also use a BackgroundWorker
var collectionData = await GetCollectionData();
foreach(var item in collectionData)
{
MyCollection.Add(item);
}
}
I'm using C# 5.0 async and await keywords for asynchronous operations, but you can also use a BackgroundWorker that does your background work.
You can also use Dispatcher.BeginInvoke() for some lighter background work (such as copying data into MyCollection), although for heavy work I find it still locks up the UI so I prefer to use background threads.
It is not possible to modify the contents of an ObservableCollection on a separate thread if a view is bound to this collection, instead you can override ObservableCollection and provide support for it and use it across your application.
This sample contains exactly what you want - http://tomlev2.wordpress.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/
When it comes to threads and ui-elements one of the most important rules to follow which may safe you a lot of trouble in the long run is to keep ui-element instantiation on the ui-thread. Surely you can manage that. And if you need to change those objects from another thread you can use the Dispatcher.
(The threading model reference may also be of interest)
Thank you everyone for your help... a guy from MS visited the company (sorry for the commercial annotation) to do other things, I stoled him and show this behavior. In a matter of 2 minutes founds the source of the problem... which I'm not sure to really understand.
It happens that I'm using an ICollectionView to display a sorted/filtered version of my problematic ObservableCollection. I was creating this ICollectionView in the constructor of my class, so at the moment of deserialization it was created in another thread. He suggested to move this creation to a further time in code (when the related property gets read). This solved the problem.
However the ObservableCollection, created in that other thread, now lets me add new item. Not sure why, but now it works.
Sorry for being this late and thank you again.

wpf MVVM ObservableCollection

My model has a couple properties one is a string and the other is an observablecolletion. When the model is created it fires off a backgroundworker thread to basically poll a .dll for data. Based on the data it receives it will either set the string and/or add and item to observable collection. My string property seems to fire its Onproperty change just fine and the view updates. However, my observable Collection throws a cross thread exception. I have tried moving code where i set the ObesrvableCollection to the worker.ReportProgress and get the same error. I have moved the logic into the view model and still get the same threading error. I'm unsure why my string property works for one. I have read about Dispatcher.Invoke, but i'm pretty sure that my model should not be aware of this. Can anyone explain the correct way to go about this please.
Just fyi - my view is not tied directly to my model. I have a property for my model in my viewModel and the model gets passed through constructor injection. Just want to put that out there before anyone thinks my model is talking directly to the the view.
Hard to give specifics without code. However, WPF automatically marshals property change notifications for scalar properties but not collections. Hence, you must be modifying the collection from a non-UI thread.
There is no reason why your VM can't use Dispatcher, or perhaps the more generic SynchronizationContext if you prefer. It can make things more tricky to test, however.
If you post code there may be a way you can simplify things.
As Kent said, if you're not on the UI you need to use the Dispatcher to update your collection:
Application.Current.Dispatcher.Invoke(new Action(() =>
{
// update your ObservableCollection here
}));

Need to force refresh on a WPF Label

I am making an asynchronous call to a web service. Since it might take a few seconds there is a status Label used to let the user know what's going on. But even though the call is async the first call seems to block for a few seconds and the status label takes too long to get updated. In WinForms I could force the label to refresh (using Update() I think) but not in WPF. Any super easy ways to get this working?
Thanks,
Gerry
You could move the entire call logic into a QueueWorkUserItem or BackgroundWorker block. That way the first proxy initialization would not block the UIThread (before the async. Begin/End pattern kicks in). Assuming that you are using databinding the object exposing the property bound to the Label implemented INotifyPropertyChanged everything should happen automagically.
I'd (wildly) guess that the blocking is due to the creation/initialization of the service proxy classes. If so, you could try to create the proxy earlier, or call your asynchronous web service in another thread.
The general answer to your question about refreshing controls... I have always relied on data binding to do this. That won't help though if the main UI thread is stuck doing something. And if the UI thread is stuck, I don't know that there's any way to get it to draw.
There isn't a way to tell the label to refresh that will actually work in your case. If the UI is being blocked, it won't refresh. Basically, when you actually get to the point where you update the label's text, it will show in WPF. The only possible exception that I can think to that would be if you are using a non-WPF control but even then it should work.
My suggestion would be to update the label before you perform the first action (even before variables are initialized, since this might be where the issue actually is). Here is a pseudocode example of what I mean (just in case I wasn't clear):
private void KickOffProcess()
{
label1.Text = "Processing ..."; //This is where you need to move the label update code
AsyncCall();
}

Resources