I haven't been able to find an example like this, though I'm sure there must be a few out there.
When the user clicks a button to log in, an event handler on the button click calls a function that logs the user in. Based on the user, they can be taken to one of many start screens. The information for which screen is returned from a service call. From what I can tell, Dispatcher.BeginInvoke is only used to update the UI thread, so the logic that determines which page to navigate to should be in the method passed to Dispatcher.BeginInvoke, right?
I need to make a service call and take action based on the result. Do I have to make the async service call first and call Dispatcher from the callback? Do I put the function that does the validation, calls the service, and handles the callback as the delegate that is passed to the Dispatcher?
Sorry if this is a basic question. The examples I've found only use the Dispatcher to update a textbox or some other trivial item. I haven't found anything where the UI thread needs to take action based on the result of an async call.
It's not clear what validation you're talking about but:
Call the service asynchronously, with a callback to execute when the service call finishes
In the callback, do whatever non-UI related work is involved, and then call Dispatcher.BeginInvoke to perform any UI-related operations.
If you need to do validation before the service call, that could be part of your button's event handler... at least as long as it isn't a long-running piece of validation.
If you could give more details about what steps are logically involved in your process, that would help.
See, Dispatcher actually holds the UI thread. As every control has strong thread affinity, you need to update this using Dispatcher.
From any thread you can access Dispatcher using DispatcherObject.Dispatcher.
this.Dispatcher.Invoke((Action)(()=>{
.//// your action
});
Now whenever you need to update the elements in the thread, you can wrap around the context to call service anytime. You can use the Background thread or you can call from inside of Dispatcher thread to invoke the Service call.
Calling From dispatcher will hold the UI if the call is synchronous. So I recommend you to do the call from the Background thread just below updating the Invoker.
All service call are asynchronous in silverlight (and hence windows phone 7) so yes, what you describe is way you do it.
Different service libraries provide different ways to call their methods - some offer a 'call complete' method, others take a event hander passed in, but either way if you want to update the UI (and I assume this includes moving page) you will need to do this on the UI thread, which is what the dispatcher is for.
Dispatcher.BeginInvoke( () => {
// This code is on the UI thread.
});
Related
In my winforms client application, I have generated asynchronous methods for my WCF service (Begin... and End...).
When the application starts, it makes async calls to the server to get and cache data that will be later used in the application (e.g. list of countries).
If the application's main thread requires this data (e.g. to fill a combobox) before the async call had a chance to complete, I would like to block the main thread until the async call had Ended. I want to avoid making redundant calls to the WCF server.
I have tried to use a Monitor/Mutex and called Monitor.Enter(countryLock) then BeginGetCountries in the main thread and Monitor.Exit(countryLock) when the EndGetCountries method is called. However, I am facing the following exception:
Object synchronization method was called from an unsynchronized block of code.
Am I supposed to call Monitor.Exit(...) on the same thread that called Monitor.Enter(...)? If yes, how can I know the owner of the Monitor object and make a call in its context?
No, you don't want really to block the main thread. What you want to do is set a flag that the operation is pending and disable parts of your UI that depend on the result. When the result is returned from the asynchronous WCF operation, you can enable those parts of the UI and populate the data.
if you block the main thread it will give the appearance that the application has halted and that will be a poor experience for your users.
Like Peter Richie said, you don't want to lock in your UI thread. A "busy" flag is all you need, really.
Secondly, trying to do this with Monitor.Enter like you describe would not work, as the same thread is allowed to enter the same monitor twice without blocking.
And if you do lock, then yes, you are supposed to call Monitor.Exit(...) on the same thread that called Monitor.Enter(...). If that was the only only problem, you could marshal this back to the UI thread with this.BeginInvoke(). But like I said, locking with Monitor in a single threaded scenario makes no sense.
Assume that I have Silverlight app doing a call to a WCF service:
void DoStuff()
{
MyProxy proxy = new MyProxy();
proxy.DoStuffCompleted += DoStuffCompleted;
proxy.DoStuffAsync();
}
void DoStuffCompleted(object sender, DoStuffCompletedEventArgs e)
{
// Handle the result.
}
DoStuff is called by the UI thread. What thread will eventually call the DoStuffCompleted method? If I invoke two async calls at the same time, is there a possibility that both the completed events are fired simultaneously, on different threads?
The callback will be invoked on the main thread. Multiple responses will not occur simultaneously. The order of the response events could be unexpected. You may want to use the overload of proxy.DoStuffAsync that accepts "user state" object:
proxy.DoStuffAsync(object userState)
This will allow you to send something unique for each call so you can differentiate which response you're dealing with. Remember that if the WCF call returns an error you have no return value - so userState may be the only way to know which call failed (if it matters).
Update:
Found some more info (on SO) on how to make it use another thread:
Silverlight web service callback performance Follow the link there to Tomek's blog for lots more info.
The Completed event will occur on a different thread than the UI Thread. Multiple Completed events may be executed simultaneously on different threads because a thread pool is used to handle results.
Asynch calls are executed in the background thread pool. For each asynch call you shall have a separate thread from the pool.
DoStuffCompleted will be executed in the background pool thread.
Now, it is important to note that this
method is called on the background
worker thread. If we want to update
the UI with the newly obtained data
(say we want to update a data grid
control to display the customer data),
we have to be careful to do this on
the UI thread. If we don't, then all
manner of strange things may happen
and we will have a difficult time
diagnosing which bug to fix (from here)
I have some code which executes a windows svc (another process) and updates the UI at the same time. The calls use BeginInvoke, like so:
Install.BeginInvoke((MethodInvoker) delegate { Install.Enabled = false; });
This is in the DoWork event handler. However, the UI still freezes up. Do I need a call to Application.DoEvents somewhere (if so, where?)? How can I eliminate the freezing?
In the button click, I have:
GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);
InstallBackgoundWorker.RunWorkerAsync();
InstallBackgroundWorker just runs the code which updates the UI etc.
What I am trying to do is call a WCF server (hosted in a windows service - this is fine), but while that is off doing its thing, update the progress bar and a label with arbitrary values in an async fashion. When I select a treenode, the event handler for selected treenode is f ired, which may cause some of the slowdown. I will try putting this in its own backgroundworker.
While you certainly could place the call to update the UI (which is what your call to BeginInvoke is doing) in the DoWork method, you shouldn't, otherwise, you really wouldn't need the BackgroundWorker class.
Rather, you would call the ReportProgress method which would then fire the ProgressChanged event.
It's in the event handler of the ProgressChanged event that you would make the call to Install.Enabled = false.
The problem is not directly related to the use of BeginInvoke. It probably has more to do with how much it is being called. You could use ReportProgress in conjunction with the ProgressChanged event, but assuming you replace all of your BeginInvoke calls with ReportProgress then you may wind up with similar problems because BackgroundWorker will automatically marshal the event handlers on the UI thread using the same mechanisms that BeginInvoke/Invoke are using anyway. I would say the quick solution is to reduce the frequency at which you are attempting to update the UI.
Personally, I think the use of BeginInvoke to update the UI with worker thread progress is way overused. And in the same regard the BackgroundWorker class promotes this suboptimal method as well. It is usually better to have the worker thread publish update information periodically to a shared data structure and then the UI thread can pick it up on its own schedule (usually by polling using a Timer). This has several advantages:
It breaks the tight coupling between the UI and worker threads that the Control.Invoke\Control.BeginInvoke imposes.
It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
The UI thread gets to dictate when and how often the update should take place.
There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).
It is unfortunate that BackgroundWorker lacks the necessary mechanisms for using this alternate approach. However, you should be okay with using ReportProgress as long as you do not call it too frequently.
The MSDN article: How to: Make Thread-Safe Calls to Windows Forms Controls
says we should use async delegate to make the call. But why does the async delegate make the call safe?
Windows controls use the Component Object Model (COM) single-threaded apartment (STA) model because those underlying controls are apartment-threaded. Furthermore, many of the controls use the message pump for many operations. This model says that all function calls to each control must be on the same thread that created the control. Invoke (and BeginInvoke and EndInvoke) marshals method calls to the proper thread.
From Bill Wagner's More Effective C#. Item 16. Understand Cross-Thread Calls in Windows Forms and WPF
You'll call control.BeginInvoke() or control.Invoke() and that method will take care of inserting your delegate in the GUI dispatch thread safely, so a bit later on your delegate will be processed and executed in the GUI thread and not the thread you'r in
The bottom line is this: You shouldn't update the UI Controls from a thread other than the one on which the control was created (UI / Main Thread). Otherwise you may see some unpredictable behavior.
If you need to update the UI from a worker thread (other than the main thread) you need to switch back to the UI Thread before updating the UI.
The article suggests using
IsInvokeRequired (which returns true if the current thread is not the one in which UI was created.) and Invoke(delegate) which runs the delegate on the correct/UI thread. This is useful when you want to update the UI in between the async process. e.g. update progress on the UI.
BackgroundWorker which executes registered handlers to its DoWork event async. on a worker thread and runs the registered handlers to its RunWorkerCompleted event on the calling thread. This is ideal if you want to update the UI with something after the async task has completed. e.g. post a Done indication on the UI
Because, windows forms controls are designed in that way, so they can be accessed only from within he thread, which owes them. And the async delegate, when used correctly, makes the call safe.
The actual answer to the given question is contained in the second paragraph of the given MSDN article =)
Access to Windows Forms controls is not inherently thread safe. If you have two or more threads manipulating the state of a control, it is possible to force the control into an inconsistent state. Other thread-related bugs are possible, such as race conditions and deadlocks. It is important to make sure that access to your controls is performed in a thread-safe way.
You should check whether you can access control immediately, without indirection ( checking the InvokeRequired property ), if you can't, you should access it asynchronously ( very simplified explanation: the system will wait until it can safely access a control )
I'm writting a Windows Forms application in C# that performs a lot of long-running procedures. I need to program the application so that the GUI doesn't lock. What is the best way to program it?
I know how to use the following:
BeginInvoke/EndInvoke
Calling Application.DoEvents() repeatedly (probably not a good idea)
BackgroundWorker
etc.
But how to manage GUI state with call backs, etc... is not trivial. Are there solutions for this (in the form of patterns or libraries)?
Using BackgroundWorker is the simplest way to do what you're trying to do. BackgroundWorker simplifies the logic of dealing with threads, leaving you with very little code you have to write. You just have to handle three events (DoWork, ProgressChanged, and RunWorkerCompleted) and follow a few principles:
Don't ever update the UI inside your long-running method. Have it call ReportProgress instead and handle the ProgressChanged event in the UI logic.
Understand that since the worker isn't running on the UI thread, an exception that your method throws doesn't automatically show up in the UI. It just gets silently written to the console. It's very important to check the Error property of the RunWorkerCompletedEventArgs when the method is done and handle (or throw) the exception. If you don't do this, you won't know that your method failed.
If the method can be cancelled, make sure that it periodically checks the CancellationPending property to see if cancellation has been requested. If it has, once it's done handling the cancellation, set the Cancel property on the DoWorkEventArgs object. Be aware that it's possible for CancellationPending to be true and Cancel to be false; this happens, for instance, when the user requests cancellation and the method finishes before it has a chance to check CancellationPending.
Correspondingly, check Cancel in your RunWorkerCompleted event handler, so that your UI can provide the proper response to what happened while the worker was running.
The examples in the documentation all show the DoWork event handler calling a method of the form. This is almost certainly not what you want to do. Separating business logic from UI is a good idea in general; in background tasks it's essential. If your long-running method is a member of a class that doesn't know that the UI even exists, there's no danger that you'll inadvertently have it call a method that updates a status bar or something.
The Model-View-Controller pattern separates the state of your UI from the visual aspects of the UI. As long as your MVC implementation is thread aware, it should solve the state management issue for you.
This is how I handle multi-threaded UI implementations.
EDIT: Here's a good post on selecting an MVC implementation for WinForms projects.
It is relatively simple to use the ThreadPool to fire off long running processes from the UI. If you want feedback you can use some event handlers to fire on certain events from the long running process, then register for them and update the UI as needed.
MVC is good, but you still need to make sure your process is firing off on a thread other than the UI thread.
All your options are syntactic sugar of doing same thing (Asynchronous execution). May be with different levels of controls. I would go with BackgroundWorker, because your GUI (handled by the main thread) will always be responsive.