Multi-thread UI in WPF - wpf

I have two UI threads, one is the main thread and the other is a background thread whose ApartmentState is STA. Each thread creates its own window and the background window has a "Cancel" button on it.
The main thread has a function which is busy and needs quite a long time to finish. I hope once the "Cancel" button is clicked, the main thread should stop the time-consuming function.
Below is the pseudo-code in main thread:
for(...)
{
//Option A: Application.DoEvents();
//Option B: Dispatcher.Invoke to update UI in background thread
if(cancel)
return; //Stop the time-consuming function
else
DoSomething;
}
The strange thing is that the click event on "Cancel" button is NOT captured or handled by the background thread. IMO, each thread has its own message queue, and when I click the "Cancel" button, this message should be queued and processed by the background thread immediately, but according to my test locally, this is not true, the background thread never handles the button click event...
Any thoughts?
BTW, I think there are two ways to overcome the above issue, one is to use Application.DoEvents, and the other is to leverage Dispatcher.Invoke. But I'm still curious why the background thread can NOT handle the message immediately. Thanks in advance.

In general, having two user interface threads is often a bad idea, and completely unnecessary.
You'd typically have a single user interface thread, and just move the actual computational work into a background thread. User interface updates would be marshaled back to the main thread as needed. BackgroundWorker is great for this in many cases.
As for cancellation, this is typically best handled using the frameworks cooperative cancelation model which is built around CancellationTokenSource and CancellationToken. These were designed with use across multiple threads in mind, and automatically handle the proper memory barriers required.

Related

WPF user interface with long processing execution hangs

I am extremely Sorry for this long post. I need some help on c# wpf issues. I have build a complicated UI(somehow) and there is some buttons... like start and stop and others.
When i click the start button a execution process starts with communicating with some protocol layer and others and it is a long process .. and during this process i have to show some notification UI like "Enter a Text", "Select Something" etc... this time i have to show some wpf window object... and after some time i have to automatically destroy the window and go with processing again.
At first i tried to run the execution in the Main window class. But it results that when the execution starts.. user can't click anything and ui doesno't respond rather just hangs. I investigate the problem... and found that UI is busy with processing in the execution on protocol layer so its not responding.
Here is my problem... can u give me some solution that...
i will have 2 button..start and stop
when i click the start button... a large process will start( like nested for loop with a large int which will continue for 50 seconds) in function named Processor.
at time of processing the function Processor will create several window and show them wait for 5-10 seconds and also destroy them. or user click;s on the window
And the whole time the stop button should be clickable so that when i click the stop button .. the process should be stop.
I tried this with backgroundworker, dispatcher... and using separate thread. but no luck. I guess i am missing something. because if i wait for some result showing a window..the window will definitely hang.. and if i separate them with different thread.. it will not communicate with each other. please give me some suggestions
Dispatcher is definitely the solution. You may need to set the Dispatcher Priority. Sharing some relevant code may also reveal some issues.
BackgroundWorker should do what you need. Set WorkerSupportsCancellation and WorkerReportsProgress to true.
I wouldn't suggest popping up multiple windows. Pop up one window to display status. In your loop in DoWork, call BackgroundWorker.ReportProgress. Then in the ProgressChanged event handler, update the status of the window.
To implement Stop:
In your DoWork method you need to check the CancellationPending property on the BackgroundWorker in your loop. When it is true you need to exit that method. On the stop button click, call BackgroundWorker.CancelAsync().

The calling thread cannot access this object because a different thread owns it

I have a WPF window in the main thread. On button clock of this window i am loading the data. Meanwhile i am using a seperate thread to display a wait screen. But i am not able to set the main window as the parent of the wait screen. It throws following error:
The calling thread cannot access this object because a different thread owns it
You want to look into the Dispatcher.Invoke method.
You could use the BackgroundWorker class to perform your asynchronous operations; it should take care of any thread affinity issues you might be having. It's as simple to use as wiring up a couple of events.
This should get you started.
Alternatively you can use Dispatcher.Invoke to perform the operation on the correct thread:
private void DoStuffOnThread()
{
Dispatcher.Invoke(new Action(DoStuffOnUIThread));
}
private void DoStuffOnUIThread()
{
// ...
}
The problem you are running into is that windows/controls have thread affinity (they are "owned" by a particular thread), and you cannot mix them between threads.
If you want the wait screen's parent to be the main window, you should create the wait screen on the main window's thread. Then, on the other thread, you can tell the wait screen to display by using Invoke.
There is a good article on cross-thread operations in WPF here (search down for Figure 4 Updating the UI):
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

Thread inconsistencies updating form control from thread

I have scenario where thread updates form's control. I followed http://msdn.microsoft.com/en-us/library/ms171728.aspx to make it work, but I was not successful.
Program creates form control(list view), and a thread to fetch information from internet(stock quotes). Whenever user selects a known symbol from other form control, that would be added in listView, this intern adds to thread to fetch quotes from internet, and a delegate would be added to for that specific symbol, thread iterates through all the watch list symbols to fetch quotes from internet whenever there is change in price, thread calls registered delegate. In that delegate I am accessing listView elements, here I am facing problems thread inconsistent issues.
To solve this problem I followed the above mentioned link,
Approach-1) In the delegate I started background worker. Same problem
Approach-2) Main program creates background worker, this worker loops around a list to update in listView. Delegate adds new updated price to list on which background worker is looping. When background worker is accessing listView again thread inconsistent problems arise.
How to resolve this problem?
When background worker is accessing listView again thread inconsistent problems arise.
Yes. This is because it shouldn't be done. A Background Worker only provides safe access to the UI the RunWorkerCompleted and ProgressChanged events. The DoWork event is still run in the non-UI thread. To access the UI from the non-UI thread, "marshal back" to the UI-thread using Control.Invoke or SynchronizationContext.Send (these should lead to further findings if used as keywords.)
Happy coding.

How Dispatcher differs from the background thread?

How does the Dispatcher concept in .NET 3.5 and WPF differ from the background thread in .NET 2.0 ?
For example what will be difference between statements below:
delegate.Invoke/BeginInvoke
AND
this.dispatcher.Invoke/BeginInvoke
The dispatcher can be thought of as a Queue that events are sent to; a dispatcher will run on the UI thread and execute events for the UI. In windows, UI controls may only be modified by the thread that created them, so any changes to the UI must be done from the UI thread - thus that is one of the critical reasons why operations that modify window elements must be sent to the UI's dispatcher.
A background thread, in turn, is a different thread than the UI. So anything run on one of these threads will not affect or block the UI.
The concept of BeginInvoke and Invoke can be thought of as follows.
BeginInvoke means: "Do this and return before it completes. I either don't care about the return value or you can call me back at this address at some point in the future."
Invoke means: "Do this and I'll sit here and wait for it to complete."
Now how this relates to dispatchers and background threads is another matter altogether. As Justin says, the Dispatcher processes a queue of things to do every time the UI thread becomes idle. A background thread that calls BeginInvoke on the dispatcher will return immediately even though the dispatcher may not have gotten around to processing. If Invoke had been used instead, the background thread would block until the UI thread completed processing. Note that in Silverlight, there is no Invoke on the Dispatcher and in most cases you probably don't want your background thread blocking while the UI thread is processing work.
Conversely, Delegate.BeginInvoke uses worker threads in the thread pool. When you're on the UI thread (or any thread really) you can call BeginInvoke and Invoke on a delegate. BeginInvoke will use a worker thread to call the delegate using the same semantics I described above. Invoke, however, would not use a different thread. It would simply invoke the delegate synchronously in the context of the calling thread and return when completed.
Be careful when using synchronous execution across threads though as this often results in deadlocks if you're not very careful.
Using the dispatcher to execute a long-running operation still causes it to execute on the UI thread, just at a different priority than the current operation. The problem here is that usually, you want your long-running operation to have as much bandwidth as is feasible. Running under the dispatcher, you're throttled by the UI.
The point of the dispatcher is to give an anchor to a background thread back to the UI so that you can for example provide an update to the UI on the progress of your operation.
If you want to run an operation in the background and defer execution to the UI, use a backgroundworker or the new task library. Use the dispatcher to marshal updates back to the UI.
The operations invoked by both methods will be placed on the event queue to be run on the UI thread. Invoke will occur synchronously and will block until the operation completes, BeginInvoke will occur asyncronously allowing the calling method to continue executing.

How to ensure that a winform closes in exactly X seconds

In my WinForms application, I need to pop up a little custom dialog that stays on the screen for X amount of seconds and then disappears. So I use a System.Threading.Timer to invoke the _dialog.Close() method once the appropriate amount of time has elapsed. This of course means that I have to do the whole "if InvokeRequired BeginInvoke" dance which isn't really a problem.
What is a problem however is that my main thread might be off doing god knows what by the time the BeginInvoke is called. It might not get around to closing the window for quite a while. I don't need the window to close at a millisecond's notice, but within a second or so is really necessary.
So my question is how does BeginInvoke actually work itself into the main thread and how can I get around this odd limitation?
If your UI thread is busy for many seconds at a time, then:
You won't be able to close a window associated with that UI thread, without peppering your code with Application.DoEvents calls (a bad idea)
Your whole UI will be unresponsive during this time. The user won't be able to move any of the application's windows, and if the user drags other windows over the top of it and off again, you'll end up with an ugly mess while the UI waits to repaint itself.
Certainly use a System.Windows.Forms.Timer instead of a System.Threading.Timer for simplicity, but more urgently, look at fixing your code to avoid having such a busy UI thread.
UPDATE: The conclusion would seem to be that utilising ['BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) along with a System.Windows.Forms.Timer would be the best approach.
Best to use System.Windows.Forms.Timer for this purpose - this is precisely the sort of application it was designed for. Add one to the pop up form and start it as soon as the form is shown, then hide the form on the Tick event. This solution won't give you any threading issues because the timer runs purely on the UI thread.
Edit: If you want to move the logic outside of your popup form, then I recommend you just create an overload for the Show method within the form code that takes a timespan for its parameter and does the job of setting the Timers's interval and starting it.
Edit 2: If you're main (UI) thread is doing too much work and therefore blocking the message pump and not allowing the timer to fire, then it's the design that's the issue I'm afraid. Your UI thread should never be blocking for more than a fraction of a second. If you need to do serious work, do it in the background using a worker thread. In this case, because you are using WinForms, BackgroundWorker is probably the best option.
Create a dedicated thread and use Application.Run to create and show your form. This will start up a message pump on the second thread which is independent of the main thread. This can then close exactly when you want it, even if the main thread is blocked for any reason.
Invoke and BeginInvoke do get into the main thread by using a window message posted into that thread, waiting for it to be processed. Therefore, if the message pump of the main thread is not processing messages (e.g. busy), it will have to wait. You can mitigate this factor by calling Application.DoEvents() when doing time-consuming operations in the main thread, but that's not really a solution to the problem.
Edit: Sample from some splash screen code (the form requires no special code or logic):
private void ShowSplashInSeparateMessageQueue() {
Thread splash = new Thread(ShowSplashForm);
splash.IsBackground = true;
splash.Start();
}
private void ShowSplashForm() { // runs in a separate thread and message queue
using (SplashForm splashForm = new SplashForm()) {
splashForm.Load += AddDestroyTimer;
Application.Run(splashForm);
}
}
private void AddDestroyTimer(object sender, EventArgs e) {
Form form = (Form)sender;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(form.Container);
timer.Tick += delegate { form.Close(); };
timer.Interval = 5000;
timer.Start();
}
Invoke just places the delegate into the message queue of the thread you want to invoke it on. You could use the Dispatcher class to insert the delegate with a high priority, but there is no gurante that this will meet you timing constraints if the thread is doing a lot of work.
But this might be an indication that you are doing to much work on the user interface thread. Not responding for a second is a pain to a user. So you might think about moving some work out of the user interface thread.

Resources