I create a background thread to do some work and, at the very end, I call a method ThreadDone(threadWorkResult) which raises an event. Currently, the event handler runs on the same background thread but I would like it to run on the main UI thread (Forms application). I searched online and found something about using attributes here but would like to know how to do this programatically. Is there any way it can be done outside the body of the handler itself?
I looked into BackgroundWorker but I have to create several threads at once so all of the respective OnWorkerCompleted event handlers become quite messy; more importantly, not all of them require the completed event. Worst case scenario I will use several BackgroundWorkers but is it possible for me to simply call a method (void aMethod()) from a background thread and force it to run on the primary UI thread?
There is a method called BeginInvoke on Windows Form controls which will execute code in the GUI thread.
I would recommend you to use BackgroundWorker thread for the background work and you can then easily handle the UI in the OnWorkerCompleted event.
Look at my answer here for more information.
Edit
You can use a delegate to hand over some tasks to MainUI thread.
public delegate void MyDelegate(object paramObject);
In the background thread call it as below.
private void aMethod(object myParam)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new MyDelegate(aMethod), new object());
return;
}
// Must be on the UI thread if we've got this far.
// Do UI updates here.
}
See here and here for references.
Related
I'm trying to do a waiting screen for my application coded in c#.
when the user click on start, to prevent possible errors just show a message in the middle, i used backgroundWorker but doesn't work like i want.
i have this:
backgroundWorker1.RunWorkerAsync(formwaiddt.ShowDialog());
the problem is the program waits until i close this dialog.
also i tried other ways like this
Can you link to a good example of using BackgroundWorker without placing it on a form as a component?
and i obtain the same result.
then anyone knows how to show a message in the middle of the screen, also i create a panel but doesn't shows it correctly, to lock the user interactions
thanks.
The simplest case is to use BackgroundWorker to create a method that matches the delegate signature, attach that method to BackgroundWorker`s DoWork event, and then call the RunWorkerAsync() method of BackgroundWorker:
// Set your cursor to busy
Cursor.Current = Cursors.WaitCursor;
BackgroundWorker backgroundWorkerExample = new BackgroundWorker();
backgroundWorkerExample.DoWork += new DoWorkEventHandler(backgroundWorkerExample_DoWork);
backgroundWorkerExample.RunWorkerAsync();
// elsewhere:
void backgroundWorkerExample_DoWork(object sender, DoWorkEventArgs e)
{
// body of the work elided
}
When the background worker thread has finished, it raises the RunWorkerComplete event on the foreground thread, so you can switch your cursor back to the normal state using:
Cursor.Current = Cursors.Default;
Alternatively, you could use the WorkerReportsProgress property to inform BackgroundWorker that the worker procedure will report progress to the foreground thread at regular intervals.
Have you tried wiring up an event on a timer, so that it runs on a separate thread to check if the process has finished?
Can anyone tell me in WPF why we need to use Dispatcher.BeginInvoke() method to update UI from DoworkEvent handler when we can update UI using ProgressChangedEvent event handler by calling ReportProgress() method in DoWork event Eventhandler?
Correct me if my understanding about Background worker and dispatcher are incorrect?
There's one rule you need to remember:
Updating the UI needs to be done from the UI thread.
Keeping this in mind, let's see what the dispatcher does and what the backgroundworker does:
Dispatcher
The dispatcher is an object that, when you call BeginInvoke, will execute the method on the thread the dispatcher was created. The Application's dispatcher is always created on the UI thread, hence this will work.
Background worker
The background worker is very similar, although it offers an event-based API:
When you call ReportProgress inside the DoWork-method, the BackgroundWorker will raise an event on the thread the background-worker was created. So if you create the Background-Worker on the UI thread, you can update the UI inside the ProgressChanged event handler.
You can safely update the UI from a BackgroundWorker's ProgressChanged handler without any need for calling the Dispatcher.
The ProgressChanged event will by raised whenever you call ReportProgress. It is executed on the thread that created the BackgroundWorker instance, which is usually the UI thread.
From the Remarks section in ReportProgress:
The call to the ReportProgress method is asynchronous and returns
immediately. The ProgressChanged event handler executes on the thread
that created the BackgroundWorker.
I have an event that is fired async via BeginInvoke - so the event handler gets its own threadpool thread. But all the code in the event handler wants to be dispatched to the UI thread - so the entire event handler code is in a Dispatcher.BeginInvoke block. This means:
Initiating thread fires event with BeginInvoke.
A new threadpool thread is created for the event handler code to run on.
The event handler immediately just posts its code async to the UI thread using
the dispatcher (Dispatcher.BeginInvoke(...all handler code...).
The temp threadpool thread returns quasi immediately - its created only to do a UI thread post.
Is there any way to restructure this to avoid the creation of this very short lived intermediate threadpool thread (I.e so the handler code just runs directly on the UI thread)?
I dont want the event to fire sycnronously (Invoke) - its used in various contexts - and it shouldn't be blocking.
Can you just call Dispatcher.BeginInvoke directly instead of using a threadpool thread?
If you don't control the code that fires the event you don't really have a choice; there is no way around the use of the thread pool thread for that short duration.
If you do control the code that fires the event you have the option of ensuring that the event handlers all run in the UI thread. While this is certainly possible, you should think long and hard about whether it should be the case. For certain event handlers it just makes sense for them to run in the UI thread (as an example, most of the events of Form run in the UI thread) and some it doesn't. If your event is on a UI control it probably makes sense for it to run in the UI thread. If it's an event of some worker class that you just happen to be using from a UI thread at the moment, it's probably a bad idea to fire the event in the UI thread (as you may, in the future, be using that worker context in a non-WPF context).
If you do want to fire the event in the UI thread it's simple enough. If you are already in the UI thread when you intend to fire the event just invoke it synchronously:
var eventCopy = MyEvent;
if(eventCopy != null) eventCopy();
If you're not in the UI thread when you wish to fire the event then marshal to the UI thread before calling the above code:
Dispatcher.BeginInvoke(()=>{ //Or just `Invoke`, if that's appropriate in context
var eventCopy = MyEvent;
if(eventCopy != null) eventCopy();
});
Based on your edit it seems you want to conditionally fire the event in the UI thread or a thread pool thread based on some specific context, rather than always firing in the UI thread.
While this is possible, you'll need to decide if it's worth it.
As an example you could look at System.Timers.Timer which has a SynchronizingObject property that allows you to determine how the events are rasied (null for the thread pool, or an object capable of marshalling to a particular context in the event of a particular UI model).
You could follow that general pattern.
There are a number of specific methods. You could capture the value in SynchronizationContext.Current at the time your worker thread was first created, and use that (possibly with a boolean value to disable capturing the source sync context if you might need to disable it, or forcably enable it).
Another option is to just have a property that accepts a SynchronizationContext, or some other mechanism of marshalling code to a given context (you could invent your own, use delegates, etc.).
I am stuck and was hoping someone could help me.
I have made a class/gui with a loading bar set to marquee so that when a task is being carried out i could display it to the user.
In one of my gui classes, in the constructor on the first line i am making a new instance of this class and then doing
LoadingBar bar = new LoadingBar();
Thread thread = new Thread(bar.Show);
thread.Start();
However, even tho the main programme thread is going off doing some more intensive stuff, this gui still seems to freeze, even if i use backround worker.
Is there anything wrong with the approach i have mentioned and if so what do i need to change?
Thanks
You need to reverse your method. The GUI needs to stay in the main thread while the work is done in a "worker thread" (typically a BackGroundWorker). Then the worker reports back to the GUI which then updates.
You'd better do the opposite. Make your intensive work in the thread (or a background worker), and show the wait screen in the main application thread.
You need to use a BackgroundWorker. Drag one onto your form, click backgroundWorker1 and set the WorkerReportsProgress property to True
Then goto the events (via the properties window) and attach handlers for
DoWork, this is where all the work that is represented by the progress bar. You will "report progress" via this and the background worker will make sure ProgressChanged is called on the UI thread.
ProgressChanged, this is where you update the UI based on progress and state data reported to the method
DoWork event looks something like this
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var userState = new StateClass();
while (working)
{
// TODO: do work here
// update the state surrounding this task via userState
userState.property = "some status";
// report the progress so that backgroundWorker1_ProgressChanged gets called
this.backgroundWorker1.ReportProgress(percentComplete, userState);
}
}
ProgressChanged event looks like this
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// e.UserState contains the state data you passed to ReportProgress,
// you have to cast it to the right type though, since its of type object
var userState = (StateClass)e.UserState;
int progress = e.ProgressPercentage;
// TODO: report progress to the UI with the above variables
}
Now all you have to do is tell the background worker to do work by calling
this.backgroundWorker1.RunWorkerAsync()
I don't think you're doing all your work within the background worker or the GUI wouldn't be freezing. We'll need to see more of your code or you'll need to have another look at background worker examples to see what could be wrong.
EDIT
Add a call to System.Threading.Thread.Sleep(1); after your report progress call
I'm writing a little chat app, and I have this event handler:
void o_Typing(object sender, EventArgs e)
{
MessageBox.Show("Fired!");
this.Text = "Fired!";
}
o_Typing is a method in a class derived from TabPage. Basically, I want each conversation to have it's own tab.
The event handlers are fired by my Chat object, which is running in another thread. I have 1 thread for UI, and another thread for each Chat conversation (to keep polling the server for new data)
When the event is fired, the MessageBox pops up, but the Tab caption doesn't change. After the event has fired once, it never fires again, leading me to believe that the event is being called in the worker thread, although it is defined in the UI thread.
How can I get my events to be called from the worker thread, and use Invoke() to get them to execute on the UI thread?
There are two options:
1) Make the event handlers thread-safe: use Control.Invoke/BeginInvoke in any event handler which needs to talk to the UI thread.
2) Make the worker thread marshal back to the UI thread before raising the event - in other words, use Control.Invoke as part of the process of raising the event, so that the event handlers will all be called in the UI thread. Depending on how your app is structured, you may not want your event-raising component to know about the UI explicitly - but when it's being constructed you can pass in an ISynchronizeInvoke (which Control implements) and your component can use that to raise its events on the right thread. Of course, that only works (simply, anyway) if every event handler is happy to run on the same thread - but that will often be the case. You'd write something like:
protected void OnFoo(EventArgs args)
{
if (sync != null && sync.InvokeRequired)
{
sync.Invoke((Action) delegate { OnFoo(args) }, null);
return;
}
EventHandler handler = Foo; // Where Foo is the event name
if (handler != null)
{
handler (this, args);
}
}
If you fire your event in code which is executed by your worker thread, then all methods subscribed to the event will be executed under that worker thread.
For GUI-elements you need to look at the Invoke-methods.
Best Regards