How to get back to UI thread after asynchronous operation - c#

I am developing two versions of the same app for both Windows Store and Windows Phone 8 using the MVVM pattern. Each app has its own View. Model and ViewModel are shared in a Portable Class Libraray. I'm doing asynchronous operations within the Model by using TPL Tasks. Due to the restrictions of the Portable Class Library, I cannot use the async and await keywords.
After a Task has finished I want to come back to the UI thread and update some properties (which will cause the ViewModel and View to update too).
This seems to me like a quite common situation so I'm a little confused why it turns out to be so hard.
I tried two different approaches:
One (does not work)
Save a reference to the scheduler before starting the operation
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
then pass it to the ContinueWith method.
myTask.ContinueWith(t => myTaskCompleted(t.Result), scheduler);
This seems to me lika a good solution but does not work. myTaskCompleted is still executed in a different thread.
Second
Now I tried to use
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, handler);
Because I cannot use the Dispatcher from the PCL directly, I pass a reference to it (hidden in a wrapper) to almost every object in the model. (Like in this answer) This finally works but it's quite complicated and ugly.
So my questions are:
Which is the recommended way to get back to the UI thread inside a Portable Class Libraray?
What is my mistake in attempt One?
I know there already are lots of questions to this topic but unfortunately nothing really solved my problem.

TPL will use a thread from the thread pool, and the UI thread is the 'main thread' which isn't on the thread pool and never becomes available to run tasks upon. Using the ContinueWith function will grab another thread from the thread pool to execute your code upon. The core of the problem you are facing is in the fact that Windows Phone does not queue property changes and will make a direct attempt to update the view. Somewhere in your code you should have a Changed function which broadcasts property changes. I'll use mine:
public void Changed(string Key) {
// Check if the property changed has subscribers.
if (PropertyChanged != null) {
// Invoke the property changed.
PropertyChanged(this, new PropertyChangedEventArgs(Key));
}
}
This Changed function will work fine under a WPF application, because WPF will queue property changes and handles them on the next UI frame update. Since Windows Phone does not, we need to establish a pattern to change this behaviour at runtime. I made a property called Dispatcher, which I allow to be set at run-time. All my broadcasts have now been changed from Changed to Dispatcher.
private Action<string> _Dispatcher;
public Action<string> Dispatcher {
get {
if (_Dispatcher == null) {
return Changed;
}
return _Dispatcher;
}
set {
_Dispatcher = value;
}
}
So now we can change the Dispatcher at run-time in our Windows Phone application. We need to write a function that postpones changes until the UI thread is active to broadcast the changes. I did this in an extension so it is a little easier to attach the UI thread safety on a ViewModel. The run-time changes will simply use Windows Phone Dispatcher to scheduele broadcasts on the UI thread. The implementation is as followed:
public static void Attach(this ViewModelStore ViewModelStore, DependencyObject DependencyObject) {
// Set the changed event dispatcher.
ViewModelStore.Dispatcher = (Key) => {
// Begin invoking of an action on the UI dispatcher.
DependencyObject.Dispatcher.BeginInvoke(() => {
// Raise the changed event.
ViewModelStore.Changed(Key);
});
};
}
The ViewModelStore is the generic class I have been using for all my view models, so this function allows me to attach the thread-safe broadcasting mechanism to all of the view models. DependencyObject is a UI-component, such as a view. Now, all you really need to do is call attach on the view model.
ProviderViewModel.Attach(this); // This is inside a Page.
All the broadcasts are not delegated to the UI-thread and invoked the next frame the UI comes in and updates everything accordingly. You won't have to worry about thread safety like this, but you need to remember to Attach a new instance of a view model in your Windows Phone application. Let me know if there are further questions, and good luck!

Related

No SynchronizationContext when calling Await in a another AppDomain

I have successfully built a plugin mechanism where I can create UI controls in a separate AppDomain and display them as part of a Form in the main AppDomain.
These UI controls do their own data loading so when I open a form about 10 different plugins get created and each needs to load its data.
Again this all works fine if I do it synchronously but I would like to use the async/await pattern in each plugin. My refresh method looks like this:
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
OnDataChanged(); <= Worker Thread :(
}
Now here starts the problem. When I enter this method I am on the main UI thread. But when the await is over I am on a worker thread so I get a cross thread exception in the OnDataChanged() method which updates the controls.
await should by default use the SynchronizationContext.Current for its continuation but since I am in an other AppDomain this happens to be NULL.
So my question is. How can I configure await to continue on the current thread, that is the UI thread?
I know I can grab a control and do Invoke() but I am also using the MVVM pattern and this is in the View Model so I don't have access to any controls there and all View Model -> View communications are done through data bindings.
I finally figured out how to get back to the UI-Thread from within a separate AppDomain, without having a handle to a control.
Since my view model is always instantiated on the UI thread, I simply grab the current dispatcher:
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher
Now in my RefreshData method all I have to do is dispatch the action I want to perform after the await.
protected async void RefreshData()
{
_data = await LoadAsync(_taskId); <= UI Thread :)
_dispatcher.Invoke(() => OnDataChanged()); <= UI Thread :)
}
This can of course be made more fancy, by encapsulating the dispatcher, etc.
The idea for this actually came from the: MVVM Light Toolkit

calling event that implements at other thread in C#

I have a class with a Socket, listens to clients to receive data. When receive new data I want to call an event (if implemented) but as you know every connection has its own thread so the event will run at that thread and you know the rest. you can not work with form controls.
How do I call the event (or invoke it). I'm really new to thread and network programing so I appreciate any example.
public class HVremotechooser
{
public delegate void NewOrder(Order order);
public event NewOrder nOrder;
//... (code elided)
public void ReceiveCallback(IAsyncResult AsyncCall) // new connection of client
{
//... (code elided)
if (nOrder != null)
nOrder(Order); // calling the event "nOrder"
//... (code elided)
}
}
thank you.
If you want to update your form from a non-UI thread, you have to invoke the action. What I normally do is the following:
private void LongRunningBackgroundThread() {
// lots of work
...
// Update my form
InvokeIfRequired(() => {
...update form...
}
}
private static void InvokeIfRequired(Action a) {
if (control.InvokeRequired) {
control.Invoke(a);
} else {
a();
}
}
See here and here
I ran into a similar problem with a Silverlight application that I was working on last week, and used the Dispatcher.BeginInvoke method. With Windows forms, it looks like it might be easier to use Control.BeginInvoke instead (although I believe that either should work): http://msdn.microsoft.com/en-us/library/system.windows.forms.control.begininvoke.aspx
You can use the typical marshling operations like Invoke or BeginInvoke to inject the execution of a delegate onto the UI thread. Just pass an instance of ISynchronizeInvoke or SynchronizationContext to your class to facilitate the marshaling.
However, I would not do that in your case. Since, presumably anyway, these callbacks are occuring because of socket events it is possible likely they are coming in hard and heavy. You definitely do not want to slam your UI thread with all of that activity. Instead, package up all of the pertinent data and put into a collection that the UI thread can then poll for using a System.Windows.Forms.Timer on a more reasonable interval.
I rip on these marshling operations all of the time. They are way overrated and overused. Remember, there are two general methods of sharing data and signaling between UI and worker threads.
Push method via Invoke or BeginInvoke in the worker thread
Pull method via System.Windows.Forms.Timer in the UI thread
The pull method can be, and often is, more elegant.
UI Threading is a UI concern. In my opinion you shouldn't worry about invoking to the ui thread in this code. Rather the consumer of the event should do the Invoke or whatever other threading stuff they happen to need to do. That way if the UI person needs to change their strategy (e.g. by using a timer) your non-UI related code wont need to change.

Custom Events and Threading

I have two different projects and in one, I have a class that defines a custom event to fire under certain conditions:
public delegate void ButtonHandler(object myObject,
GuitarArgs myargs);
public event ButtonHandler OnButtonPress;
... other stuff ...
GuitarArgs myArgs = new GuitarArgs( guitarState );
if(OnButtonPress!= null)
OnButtonPress(this, myArgs);
Then in another project I create an instance of this class and subscribe to this event:
Guitar.OnButtonPress += Guitar_OnButtonPress;
The event then fires properly, but it seems to be on a different thread, because when I try to access some UI elements, I get an error : The calling thread cannot access this object because a different thread owns it.
The code throwing the error is:
void Guitar_OnButtonPress(object myObject, Guitar.GuitarArgs myargs)
{
GuitarCheck(myargs.State);
}
private void GuitarCheck(GuitarState getState)
{
if (getState.green)
{
VisualTreeHelper.HitTest(guitarCanvas, null,
MyHitTestResult,
new GeometryHitTestParameters(
new RectangleGeometry(new Rect(1, 411, 88, 78))));
}
}
What can I do to make this run?
Thank you.
You need to check if your event handler is running on a non-UI thread and, if so, invoke it on the UI thread:
How to update the GUI from another thread in C#?
I would like to highlight the less-upvoted answer, which provides a very elegant approach using an extension method. I use this in all of my WinForms projects (and use a variant in WPF/Silverlight projects)
https://stackoverflow.com/a/3588137/141172
If you are using WinForms
this.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx)
If you are using WPF
this.Dispatcher.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx)
So you have an event called OnButtonPress whos event handler is obviously executing on a thread that is not hosting VisualTreeHelper. The big question for me is...why? With a name like OnButtonPress it makes me think it should already be on the UI thread. Afterall, it is a button press right? So why is it executing on another thread to begin with?
Using a marshaling operation like Invoke or BeginInvoke is fine as long as you are aware of why it is needed and what it accomplishes for you. But, you really need to take a step back and identify what all is going on that would cause you to need to use a marshaling operation in the first place. There may be a bigger issue here that you need to address.

Is BackgroundWorker the only way to keep a WCF/WPF application responsive?

Client/server desktop application using C#, WCF, WPF. Since pretty much every action is going to require a trip to the server (list/create/save/delete/etc), every action has the potential to freeze the entire UI. Here's an example of a naive implementation with a call to service.GetAll() which could take a "long" time (more than a few hundred milliseconds):
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
vm.Users.Clear();
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}
(Aside: I'd love to know why List has AddRange and ObservableCollection doesn't.)
BackgroundWorker to the rescue:
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
e.Result = service.GetAllUsers();
};
worker.RunWorkerCompleted += (s, e) =>
{
vm.Users.Clear();
foreach (var user in (List<UserDto>)e.Result)
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
};
worker.RunWorkerAsync();
}
(Aside: code above has been simplified, but that's the gist of it.)
The code using BackgroundWorker works exactly how I want it to. The app remains responsive at all times, and the button is disabled for the duration of the call. However, this means adding 15 lines to every possible action the user might make.
Say it ain't so.
No, BackgroundWorker is not the only way, but it's one way. Any other way will allso include some form of asynchronous construct with the need to use Dispatch.BeginInvoke to update the UI. You could for instance use the ThreadPool:
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
});
If this is a recurring pattern (a button will trigger some action that should be performed asynchronously, with the button being disabled during the process) you can wrap this into a method:
private void PerformAsync(Action action, Control triggeringControl)
{
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = false; });
action();
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = true; });
});
}
...and call it:
PerformAsync(() =>
{
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}, btnRefresh);
As an option to using the ThreadPool, you should also perhaps look into the Task Parallel Library.
When doing this you should pay attention to how you handle UI state. For instance of you have more than one control which triggers the same action, make sure that all of them are disabled during the action.
Note: these are just quick ideas. The code has not been tested so it may contain errors. It's more to be regarded as discussion material than finished solutions.
WCF provides the ability to make all service calls asynchronously. When you create the service reference in your project, the add service reference dialog box has an "Advanced..." button. Clicking that you will see the option for "Generate Asynchronous operations". If you click that check-box then every operation will be generated in both a synchronous and asynchronous manner.
For example, if i have an operation "DoSomething()" then after checking this box i will get code generated for calling DoSomething() and DoSomethingAsync().
You will also get a Service.DoSomethingCompleted event that you can use to define a callback handler when the service call returns.
This is the method we used to make service calls without locking the UI.
Here is a rather complicated example provided by Microsoft on how to do this: http://msdn.microsoft.com/en-us/library/ms730059.aspx
It is not the only way. I recommend Task (or one of the higher-level abstractions for Task, such as Parallel or PLINQ).
I have a review of various approaches to asynchronous background operations on my blog.
The current state of things does require some boilerplate code, regardless of which approach you choose. The async CTP shows where things are going - towards a much, much cleaner syntax for asynchronous operations. (Note that - at the time of writing - the async CTP is incompatible with VS SP1).
Well, BackgroundWorker is not the only option you have but in order to accomplish what you want you still need to use multiple threads or asynchronous operations in order to not block while you wait for the long-running operations to finish.
And, because WPF requires that all code accessing the UI run on the same thread you do have to do some context switching when you call or access data or code on the UI thread. The way to ensure a call will run on the UI thread in WPF is to use the Dispatcher class.
Another simple way of keeping the UI responsive is to queue work item on a thread in the Thread Pool which is done using the ThreadPool class.
// assuming the the following code resides in a WPF control
// hence "this" is a reference to a WPF control which has a Dispatcher
System.Threading.ThreadPool.QueueUserWorkItem((WaitCallback)delegate{
// put long-running code here
// get the result
// now use the Dispatcher to invoke code back on the UI thread
this.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)delegate(){
// this code would be scheduled to run on the UI
});
});
As always, there's more than one way to skin the cat but be aware that each technique has advantages and disadvantages. For instance the method outlines above could be useful because it doesn't have that much code overhead but it may not be the most efficient way in may cases.
Other options are available including using the BeginXXX - EndXXX methods of the classes you're using if they provide any (such as the SqlCommand class has BeginExecuteReader EndExecuteReader). Or, using the XXXAsync methods if the classes have that. For instance the System.Net.Sokets.Socket class has ReceiveAsync and SendAsync.
No this is not the only option. This question is more about how are you designing your application.
You can take a look at Windows Composite Applicaiton Framework (Prism), which provides features like EventAggregator which can help you publish application wide events out and subscribe it at multiple locations within your app and take actions based on that.
Also as far as being worried about having too many lines of code, you may want to layer your application architecture in such a way that you can refactor and reuse as much code as possible. This way you have these background workers handling all your service responses in one layer while you can leave your UI layer detached from it.
No it's not the only way, but it is one of the simpler ones (at least compared to setting up your own thread, or pushing a task to a thread pool thread and arranging an event on completion).
You might be able to simplify a little bit by writing a static method somewhere that takes two parameters, the callback functions, and handles the rest for you, that way you won't have to write all the same boiler plate every time you need to make an async call.
No, certaily not.
You can create a raw Thread and execute time taking code in it and then dispatch the code to the UI Thread to access/update any UI controls.More info on Disptacher here.
Refer to this for a great information about Threads in c#.

GUI update when starting event handler class on separate thread?

We have a DLL that monitors changes in status and looks for events from a separate, purchased product. Actually, it is a ScreenPop API from Siemens, for those of you who may know what that is. I am using C#.NET 3.5 as the platform.
This API takes a looong time to initialize, so we want to use a separate thread to initialize it. Currently, we have the functionality in a class called ScreenPop. The class monitors 2 events, a status change event and a screen pop event (data that tells us who the customer is that is calling).
The way this is currently implemented doesn't work, or at least doesn't work reliably. Within the ScreenPop class, there is an initialization method where all the long-running startup code is placed. This is called from the constructor of the class, like this:
public ScreenPop( string Address, int Ext, CallbackStatusType pStatusFunc,
CallbackScreenPopType pPopFunc
)
{
CallbackStatus = pStatusFunc;
CallbackPopup = pPopupFunc;
Thread t = new Thread( StartInBackground );
t.Start();
}
In the GUI code, the func at pStatusFunc updates a status label, and the func at pPopupFunc will fire off some other code to do the screen pop - right now it just displays the data from the event.
There is a lot of glue missing, but I hope you get the point. The problem with this approach is the GUI is not updated. I know the events fire and the event handlers run, and the callback functions are getting called and they seem like they should be running, but the GUI is never updated.
So, my question is, should I abandon this in favor of a BackgroundWorker approach? Or am I just missing something in getting the GUI to update?
More info on request...
Thanks,
Dave
You can never update the GUI from a different thread - only from the UI thread, which is the one that started the application. You need to use the Control.Invoke method to run code on the UI thread. Form instance, frmMain.Invoke.
You cannot use WinForms in a multithreaded apartment, to get around this, you have to marshal over to the UI thread to perform actions on it or get results. Since you are using C#3.5, you can make use of lambdas, generics, and extension methods to make a really clean and easy to use solution.
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
if (control.InvokeRequired)
{
return (TResult)control.Invoke(func, control);
}
else
{
return func(control);
}
}
}
Now you can safely and easily make changes or get values.
this.InvokeEx(f => f.label1.Text = "Hello from another thread");
new Thread(() =>
{
string formTitle = this.InvokeEx(f => f.Text); // Safely get form title
}).Start();

Categories