Convert a WPF dispatcher to Winforms BGworker? - wpf

i recently acquired some source code for a console wrapper for a server. The program was originaly in WPF and part of the code was:
private void ServerProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
}));
}
private void ServerProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
ParseServerInput(e.Data);
}));
}
Its also had this annotation in both voids:
// You have to do this through the Dispatcher because this method is
called by a different Thread
However in WinForms there is no such thing - is there a way to change this to a Background worker or something (Ive barely done any multi-threading)?

Both methods are event handlers. Chances are they are from some kind of listening code and I would expect that they are called from a non UI thread (eg normally a threadpool thread that is doing the listening). You can check that by putting a break point and looking at the threads window in the debugger.
So you will need to apply the winforms way of updating the UI from a non UI thread.
If you search SO you should find quite a lot on how to do that. E.g
Updating UI from a different thread
How to update GUI from another thread in C#?

Some background: A process that is running in a thread other than the UI thread is not allowed to access any UI controls directly. Your WPF ServerProc is running in a different thread than your UI which requires the Dispatcher to help you communicate from the ServerProc thread back to the UI controls in your UI thread.
If your ServerProc -- in WPF or WinForms -- were running in the UI thread, you would not need to surround it with the Dispatcher.Invoke call.
For you, you can put your ServerProc in a BackgroundWorker (MSDN example). Your DoWork method would contain the meat of the code doing the work and then depending on how the ServerProc does its work, you might be able to use ProgressChanged to do what both your sample WPF methods are doing. ProgressChanged has a parameter passed in that you would indicate if it were an error or data has been received and inside the function you could display the appropriate info. Take a look at the MSDN docs because they have a good example.
What's important to point out is that ProgressChanged happens on the UI thread so you do NOT need to surround your calls to your UI controls with Invoke; just call them normally. Same goes for RunWorkerCompleted which may be the other option for displaying data when your ServerProc has finished its job.
Finally, if you actually had to access a UI control from within your thread, you do something very similar looking as your WPF code sample. Look at MethodInvoker. Instead of Dispatcher, you're really just calling it from your main Form.

Related

UI thread vs. BackGroundWorker thread

Im reading a WPF book and I see this code:
private void bgw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int percenti;
percenti = e.ProgressPercentage;
progressBar1.Value = percenti;
}
The question is simple.
if
ProgressBar belongs to UI Thread and
BackGroundWorker works with a Background Thread
Why are there no errors (like: The calling thread cannot access this object because a different thread owns it.)?
thanks.
Why are there no errors (like: The calling thread cannot access this object because a different thread owns it.)?
This is one of the main advantages to using BackgroundWorker. The BackgroundWorker component automatically marshals calls for progress and completion back to the synchronization context (thread) that starts the job.
In this case, that means that the event handlers for ProgressChanged (and the completion event) happen on the WPF UI thread.
The BackgroundWorker handles the thread context switch for you. The event BackgroundWorker.ProgressChanged will be raised on the UI-Thread and hence your callback bgw1_ProgressChanged will be called in the context of the UI-Thread.
This was the main purpose for the BackgroundWorker's existence: To make async work easy and straight forward in conjunction with a UI.
BackgroundWorker exists since .NET 1.0. Now that we live in 2012, we have the Task class and the Task Parallel Library and soon the c# async keyword as general means for everything async, wich makes the BackgroundWorker kind of obsolete or at least old school.
It is because you cannot make changes in the Do_work method of the background worker.
progress_changed event keeps updating what is happening in the other thread.
Bes to clear your concept through this link-->
[https://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners][1]

Application Dispatcher and Control Dispatcher

Assume i have control button with name "button1" and function with name "doSomething". Function "doSomething" is called from another thread.
i have two method to call function doSomething from UI thread.
First, from control button dispatcher
this.button1.Dispatcher.BeginInvoke(new Action(() => { doSomething(); }));
and Second, from application dispatcher
this.Dispatcher.BeginInvoke(new Action(() => { doSomething(); }));
The result is same, what is the real different ?
The same dispatcher instance is referenced in all controls owned by the same thread. There is no difference.
All of UI controls (which were created normally), share the same dispatcher instance. That dispatcher is working on UI thread. If you create some control on backgroud thread, it will create new dispatcher on that thread, and this will not be very good.
The best way to avoid most problems with threading and UI controls both in WinForms and WPF is to use System.Threading.SynchronizationContext.Current. The workflow is simple: you get System.Threading.SynchronizationContext.Current while you are on UI thread and save it somewhere (for example in a public static field). Then, whenever you want to run some code on UI thread, you access that persisted SynchronizationContext intance and use its Send or Post methods. It will run you delegates on thread, where SynchronizationContext was achieved (for current case on UI thread). Also it is smart enough, to use the current way of Invoking (message loop for WinForms and dispatcher for WPF) and also if you are already calling from UI thread it will just run your delegate synchronously.
Just keep in mind, that you should get SynchronizationContext only after you create your first control on the current UI thread, because SynchronizationContext will be initialized right after that.
In most of the case, We have single UI thread. So, It doesn't make difference you call
control.Dispatcher(which comes inherited from DispatcherObject parent of the controls).
or
Disptacher.Current.
But there are scenarios, where you will end up having multiple dispatchers.
So, in that situation, Control.Dispatcher will help as It will find out the current dispatcher to respect Thread Affinity. In this Dispatcher.Current won't help.
One scenario, having dedicated thread(with dispatcher) for displaying busy indicator as default UI thread is busy in rendering large list of controls.
However, with SynchronizationContext is another way to avoid such issues. but what if that context or thread is no longer required or it has been set to null by any other developer. So, It is always wise to go for Control.Dispatcher in my opinion.

WPF: Is there a simple way to create a Progress Window?

I tried creating one, but the BackgroundWorker in Window1 couldn't access the ProgressBar in Window2 once the reportProgress was activated, because "The calling thread cannot access this object because a different thread owns it".
Seems there's a lower level thread model I could use, but it also seems a lot more complicated.
You just need to get the ProgressBar disptacher.
You can access the ProgressBar with:
Window2.prograssbar.Dispatcher.Invoke(
() => /*the code for modifying the progressbar*/ );
In WPF, UI controls and properties may only be activated from the UI thread. In order to change the progress bar's value from a different thread, you can add a command to the GUI thread's dispatcher queue. You can do this by passing a delegate to the Dispatcher.Invoke() method. See the article at http://msdn.microsoft.com/en-us/magazine/cc163328.aspx for more details.
You need to look into Delegates

.NET Compact Framework: how to ensure form is visible before running code?

We've got a Model-View-Presenter setup with our .NET Compact Framework app. A standard CF Form is implementing the view interface, and passed into the constructor of the presenter. the presenter tells the form to show itself by calling view.Run(); the view then does a Show() on itself, and the presenter takes over again, loading up data and populating it into the view.
Problem is that the view does not finishing showing itself before control is returned to the presenter. since the presenter code blocks for a few seconds while loading data, the effect is that the form is not visible for a few seconds. it's not until after the presenter finishes it's data load that the form becomes visible, even though the form called Show() on itself before the presenter started its data loading.
In a standard windows environment, i could use the .Shown event on the form... but compact framework doesn't have this, and I can't find an equivalent.
Does anyone know of an even, a pinvoke, or some other way to get my form to be fully visible before kicking off some code on the presenter? at this point, i'd be ok with the form calling to the presenter and telling the presenter to start it's data load.
FYI - we're trying to avoid multi-threading, to cut down on complexity and resource usage.
The general rule is: never do anything blocking on the UI thread
The UI in Windows (and in Windows CE as well) has an asynchronous nature. Which means that most API calls do not necessarily do whatever they're supposed to do immediately. Instead, they generate a series of events, which are put into the event queue and later retrieved by the event pump, which is, essentially, an infinite loop running on the UI thread, picking events from the queue one by one, and handling them.
From the above, a conclusion can be drawn that if you continue to do something lengthy on the UI thread after requesting a certain action (i.e. showing the window in your case), the event pump cannot proceed with picking events (because you haven't returned control to it), and therefore, your requested action cannot complete.
The general approach is as follows: if you must do complex data transformation/loading/preparing/whatever, do it on a separate thread, and then use Control.BeginInvoke to inject a delegate into the UI thread, and touch the actual UI controls from inside that delegate.
Despite your irrational fear of "complexity" that multithreading brings with it, there is very little to be afraid of. Here's a little example to illustrate the point:
public void ShowUI()
{
theForm = new MyForm();
theForm.Show();
// BeginInvoke() will take a new thread from the thread pool
// and invoke our delegate on that thread
new Action( PrepareData ).BeginInvoke(null,null);
}
public void PrepareData()
{
// Prepare your data, do complex computation, etc.
// Control.BeginInvoke will put our delegate on the UI event queue
// to be retrieved and executed on the UI thread
theForm.BeginInvoke( new Action( PutDataInTheForm ) );
}
public void PutDataInTheForm()
{
theForm.textBox1.Text = "data is ready!";
}
While you may play with alternative solutions, the general idea always remains the same: if you do anything lengthy on the UI thread, your UI will "freeze". It will not even redraw itself as you add new UI elements on the screen, because redrawing is also an asynchronous process.
Therefore, you must do all the complex and long stuff on a separate thread, and only do simple, small, guaranteed to run fast things on the UI thread. There is no other alternative, really.
Hope this helps.
If your key problem is that the form won't paint before your presenter data loading methods are completed, and you have a call to this.Show() in your Form_Load, try putting Application.DoEvents() directly after this.Show() to force/allow the form to paint.
protected void Form_Load(blah blah blah)
{
this.Show();
Application.DoEvents();
... data loading methods ...
}
No need to create another thread if you don't want to (although a couple of seconds have to be dealt with somehow).
You can use the activated event. Because it will fire when the form is activated, you need a boolean local to the form to check wether or not the form has been created for the first time.
Another option for you is to disconnect the event handler right after you finish presenting the form.

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