I am working on a WPF project where I have to import data from a lot of single files.
The actual importing of those files and the data in them is being done in a backgroundworker doWork method.
It works like a charm, does the job and updating a progress bar also works perfectly.
Now though, depending on what I encounter in those files, I occasionally need to get a decision from the User before I can proceed processing the current file.
What is the best way to open a window/dialog, getting the values set in there back into the backgroundworker.doWork method and continue processing?
Is that even possible with a backgroundworker or do I need to keep that processing logic in the main/UI thread and update the progress bar from there somehow?
I hope some of you can give me some hints or point me to other resources since I have not found much useful information for my specific problem.
Background worker works in a different thread. You can not invoke UI directly from a background thread. One way of achiving what you are trying to do is by using a flag and Dispatcher to invoke UI for user input
bool WaitFor_Input = false; //flag to indicate user input status
private void ThreadRun()
{
//THIS IS IN Background worker thread
//do task
WaitFor_Input = true;
//ask for user input
Dispatcher.BeginInvoke(new Action(Show_Dialogue), null);
while (WaitFor_Input); //Background worker waits untill user input is complete
//continue further processing
}
private void Show_Dialogue()
{
//THIS IS IN UI THREAD
//show your dialogue box here, update data variables
//finally set
WaitFor_Input = false;
}
Keeping processing logic in a background thread is actually a good idea.
You can call the ShowDialog of an OpenFileDailog class on a new Thread or BackgroundWorker( this will also create a new thread)
But when you want to pass or update any property or control that is running on the main thread you will need to use the Disptacher like this
Dispatcher.BeginInvoke(new Action(() => { YourMethodThatUpdatesSomething(); }));
Related
In WinForms application I start worker thread that adds data to root a XElement.
Then in main thread I need to wait while worker thread finishes it's work (to get complete XElement), and output this XElement to a textarea.
If I call .Join() on the main thread - it freezes until another thread stops (and user can't click any button on the main form).
Is it possible to unblock main thread while waiting for another thread to finish it's work??
I've tried:
1.
BeginInvoke(new Action(() => {
XmlManager.whReady.WaitOne();
xDocString = xResultDoc.ToString();
}));
2.
string xDocString = String.Empty;
new Thread(() => { xDocString = XelementToString(); }).Start();
txtXmlTree.Text = xDocString;
public string XelementToString() {
XmlManager.whReady.WaitOne();
return xResultDoc.ToString();
}
But it had no effect.
EventWaitHandle XmlManager.whReady.WaitOne(); is being .Set() in the worker thread just before it closes.
Yes, you can use async/await
string docString = await Task.Run(() => {
XmlManager.whReady.WaitOne();
return xResultDoc.ToString();
}).ConfigureAwait(true);
//Execution flow will resume here once the thread is done.
....
//Now do something here with the text (e.g. display it).
...
For example, if you want to run this on a button click, you would have (note the async modifier):
private async void button1_Click(object sender, EventArgs e)
{
...The code above goes here...
}
As to why your code is not working as expected (both of your attempts):
Your code is blocking, because it causes the action to be executed on the thread on which the main form's handle was created (so the UI thread). You typically call BeginInvoke from another (non UI) thread to tell the UI to do something.
You start a thread and then immediately expect to have xDocString ready to use. It doesn't work that way. By the time this line is executed txtXmlTree.Text = xDocString; the thread may or may not have finished executing (most likely not finished).
I hope now you see why await is a way better option. You don't have to synchronize your workers with the main thread, you don't have worry about context switching and making sure UI code executes on the UI thread.
You can use BackgroundWorker class since it's a WinForm application.
The BackgroundWorker will let the sub-task to be run in the background, and notify the main form on it's completion (as well as progress, if needed), so the main form will be able to display the output in the text area once the sub-task is complete.
I have a multi threaded app where I have created a Producer/Consumer Pattern for the processing of XML files etc
What I want to know is what would be a good approach for updates to the UI and when the process finshed.
Should I go down a threaded approach and create Barrier and wait for all tasks to complete or should I just create an event/delegate and get the UI to catch this for both UI updates/compeltion
You may checkout Signalr which allows you to achieve PUSH notifications to clients.
Sorry, this answer was assuming Windows Forms, because there was no asp.net tag at first. Hopefully someone will provide a good answer for asp.net as well.
You can use Form.Invoke() to update stuff from the non-GUI thread, here's a simple example:
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(DoStuff);
thread.Start();
}
void DoStuff()
{
Thread.Sleep(1000);
this.Invoke(new Action(() => MessageBox.Show("Hey, this was invoked")));
}
With Invoke, you can do just about anything with the Form, it runs the invoked action in the form's thread. So you can change your status text or whatever that way. Of course, you shouldn't have your "business logic" inside the Form class, and you shouldn't use Thread.Sleep, I'm just showing the very basic fact that you can call back to the UI thread this way.
As to whether you should wait for all tasks to complete before doing anything, or show status updates as they execute, that's really up to you. I like to show updates on the UI when possible so the user knows what's going on. It's also good to have a progress bar going if there's something happening that the user might be waiting for. The progress bar can just be a marquee if you don't have a good way to indicate real progress.
I am currently trying to update a chart which is on my form to the background worker using:
bwCharter.RunWorkerAsync(chart1);
Which runs:
private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
System.Windows.Forms.DataVisualization.Charting.Chart chart = null;
// Convert e.Argument to chart
//..
// Converted..
chart.Series.Clear();
e.Result=chart;
setChart(c.chart);
}
private void setChart(System.Windows.Forms.DataVisualization.Charting.Chart arg)
{
if (chart1.InvokeRequired)
{
chart1.Invoke(new MethodInvoker(delegate { setChart(arg); }));
return;
}
chart1 = arg;
}
However, at the point of clearing the series, an exception is thrown.
Basically, I want to do a whole lot more processing after clearing the series, which slows the GUI down completely - so wanted this in another thread.
I thought that by passing it as an argument, I should be safe, but apparently not!
Interestingly, the chart is on a tab page. I can run this over and over if the tabpage is in the background, but if I run this, look at the chart, hide it again, and re-run, it throws the exception. Obviously, it throws if the chart is in the foreground as well.
Can anyone suggest what I can do differently?
Thanks!
EDIT:
I know that this can be done in the form thread, as when I assign it back again. However the whole point of using a background worker is to avoid grinding the whole program to a halt. As I said, there is a lot more processing than just this one command.
I assumed that passing it as an argument would allow me to access it in that thread unhindered, but is there a chance that this passed chart still points back to the original chart in some way? If so, how can this be overcome?
I want to block the GUI thread as little as possible - so there seems no point in just invoking every command.
If you want to clear it first, then do a lot of asynchronous work before you redisplay it, why don't you call chart.Series.Clear(); before you invoke the BackgroundWorker? In that case it gets cleared on the main UI thread, then you perform som async work before you again set the chart from the UI thread.
Also, when using a BackgroundWorker, I would use the inbuilt ReportProgress and WorkerCompleted events to avoid the manual cross-thread invoking. That's part of the reason of using the BackgroundWorker in the first place to get this kind of functionality for "free". So setting the chart should be done in the WorkerCompleted to simplify your code (even if that is not the source of the problem in this case).
Check for Invoke Required in bcCharter_DoWork, if yes put the Clear method call in a delegate too.
if (InvokeRequired)
{
Invoke(new MethodInvoker(delegate
{
chart.Series.Clear();
e.Result=chart;
}));
return;
}
I agree with the analysis in the previous posts : you ask a thread to access to a resource of another thread.
Like you used a BackgroundWorker I suggest you to use the Dispatcher :
private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
Chart chart = null;
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
chart.Series.Clear();
}));
}
The problem you are encountering is that you cannot access UI elements on threads other than the one they were created on. However, in your case you can simply clear the chart before calling the background worker.
You can manually marshal UI element access to the correct thread from another thread using Control.Invoke.
I have a windows forms application
on which I need to use a for loop having a large number of Remote Calls around 2000 - 3000 calls,
and while executing the for loop, I loose my control on form and form controls, as it becomes a large process and some time it shows "Not Responding" but if I wait for a long it comes back again, I think I need to use some threading model for that, is there any idea, how can I proceed to solve the issue?
You need to perform the long running operation on a background thread.
There are several ways of doing this.
You can queue the method call for execution on a thread pool thread (See here):
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
In .NET 4.0 you can use the TaskFactory:
Task.Factory.StartNew(() => YourMethod());
And in .NET 4.5 and later, you can (and should, rather than TaskFactory.StartNew()) use Task.Run():
Task.Run(() => YourMethod());
You could use a BackgroundWorker for more control over the method if you need things like progress updates or notification when it is finished. Drag the a BackgroundWorker control onto your form and attach your method to the dowork event. Then just start the worker when you want to run your method. You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Create a totally new thread for your work to happen on. This is the most complex and isn't necessary unless you need really fine grained control over the thread. See the MSDN page on the Thread class if you want to learn about this.
Remember that with anything threaded, you cannot update the GUI, or change any GUI controls from a background thread. If you want to do anything on the GUI you have to use Invoke (and InvokeRequired) to trigger the method back on the GUI thread. See here.
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker is the easiest way.
Obviously, you need to use background threads. I suggest you read this free e-book.
I want to otherwise block code execution on the main thread while still allowing UI changes to be displayed.
I tried to come up with a simplified example version of what I'm trying to do; and this is the best I could come up with. Obviously it doesn't demonstrate the behavior I'm wanting or I wouldn't be posting the question. I just hope it gives some code context to back my poor explanation of the problem I'm hoping to solve.
Within a button click handler on a form I have this:
private void button2_Click(object sender, EventArgs e)
{
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
new Thread(delegate()
{
// do something that takes a while.
Thread.Sleep(1000);
// Update UI w/BeginInvoke
this.BeginInvoke(new ThreadStart(
delegate() {
this.Text = "Working... 1";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
// Update UI w/Invoke
this.Invoke(new ThreadStart(
delegate() {
this.Text = "Working... 2";
this.Refresh();
Thread.Sleep(1000); // gimme a chance to see the new text
}));
// do something else that takes a while.
Thread.Sleep(1000);
autoResetEvent.Set();
}).Start();
// I want the UI to update during this 4 seconds, even though I'm
// blocking the mainthread
if (autoResetEvent.WaitOne(4000, false))
{
this.Text = "Event Signalled";
}
else
{
this.Text = "Event Wait Timeout";
}
Thread.Sleep(1000); // gimme a chance to see the new text
this.Refresh();
}
If I didn't set a timout on the WaitOne() the app would deadlock on the Invoke() call.
As to why I'd want to do this, I've been tasked with moving one subsystem of an app to do work in a background thread, but still have it block user's workflow (the main thread) only sometimes and for certain types of work related to that subsystem only.
You want to use the "BackgroundWorker" class, which will take most of this pain out of this for you.. but as mentioned before, you'll also want to structure it so that the main thread is updating the UI and the worker is doing the heavy lifting.
It is easyer then you might think.
Suggestion: when you need a thread to perform some occasional work, get it from the threadpool, so you will not need strange/error prone recycling code.
When you want something on another thread to update your UI, you just need a reference to the form and to call Form.Invoke passing the UI code you want the main thread to execute; it's a best pactice, in an event, to release the UI thread as soon as possible.
Ie:
private void button1_Click(object sender, EventArgs e)
{
// this is the UI thread
ThreadPool.QueueUserWorkItem(delegate(object state)
{
// this is the background thread
// get the job done
Thread.Sleep(5000);
int result = 2 + 2;
// next call is to the Invoke method of the form
this.Invoke(new Action<int>(delegate(int res)
{
// this is the UI thread
// update it!
label1.Text = res.ToString();
}), result);
});
}
Hope this helps you:)
EDIT: I am sorry, I didn't read the "blocking user workflow" part.
WindowsForms is not designed to do that, blocking the main thread is BAD (it handles the messages from the OS).
You don't have to block the user workflow via freezing a form (which would then be considered "Not Responding" by windows), the way to block user workflow is by disabling any control you want (with the Invoke method above if from another thread), even the entire form!!
Common activities which 'block' the main thread are things like opening messages boxes or modal dialog. The main code appears to block at the MessageBox or ShowDialog call.
The way those items work (and MessageBox is just a specialized modal dialog) is that they contain their own message pump while they're blocking.
Although it's a nasty hack, you can do something like this in your app by looping calling Application.DoEvents() to keep the user messages pumping while you're waiting for your other task to complete. You need to be careful because all sorts of nasty things might lead from pumping messages like this - for example someone close the form or reenter your current message handler - the modal dialogs avoid this by effectively disabling input from the form which launches them.
I did mean to say that BackgroundWorker is a better solution, if you can make it fit. I sometimes combine it with a modal 'progress dialog' to give me the background thread / message pumping and the blocking of the UI thread.
Edit - to expand on the last bit:
One approach I've used is to have a 'progress form' class, which takes a BackgroundWorker object as a constructor parameter, and contains handlers for the progress and completion events of the background worker which gets passed to it.
The form which wants the work done creates the background worker and hooks up the 'work' event (can't remember what it's called right now), and then creates a progress dialog to which it passes the background worker. It then modally shows the progress dialog, which means it will wait (but pumping messages) until the progress dialog closes.
The progress form is responsible for starting the BackgroundWorker from its OnLoad override, and closes itself when it sees the BackgroundWorker complete. Obviously you can add message text, progress bars, cancel buttons, whatever to the progress form.
structure your app so that the main thread only performs UI updates, and all other work is done on secondary threads via a work queue; then add a waiting-for-godot flag to your main thread and use it to guard the method that adds items to the work queue
out of curiosity: why do you want to do this?
You should probably restructure your code as others have suggested, but depending on the behavior you're looking for, you might also want to have a look at using a Thread.Join on your background worker thread. Join actually allows the calling thread to process COM and SendMessage events while it waits for the other thread to finish. This seems like it could be dangerous in come cases, but I've actually had a couple scenarios where it was the only way to wait for another thread to finish cleanly.
Thread..::.Join Method
Blocks the calling thread until a
thread terminates, while continuing to
perform standard COM and SendMessage
pumping.
(from http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx)
I agree with the others that are suggesting you use Background Worker. It does the heavy lifting and allows the UI to continue. You can use the Report Progress of Background Worker to initiate times where the Main Form can be set to be disabled while it performs the actions in the background and then re-enable once the 'certain instances' have completed processing.
Let me know if this helps!
JFV
If you could adjust your code so that you set a flag once a process has begun and then check that in the UI before you start an additional operation I think you'd have a much easier time coding this. I would create a delegate that could be called from the thread in the threadpool or user created thread to update on progress in the UI. Once the background process has been completed switch the flag and now normal UI operations can continue. The only caveat you need to be aware of is that when you update UI components you must do it on the thread they were created on, the main/UI thread. In order to accomplish this you can call the Invoke() method on any control that lives on that thread and pass it the delegate and parameters you need to call it.
Here's a link to a tutorial I wrote some time ago about how to use Control.Invoke():
http://xsdev.net/tutorials/pop3fetcher/
Just a code snippet: don't have much time sorry :)
private void StartMyDoSomethingThread() {
Thread d = new Thread(new ThreadStart(DoSomething));
d.Start();
}
private void DoSomething() {
Thread.Sleep(1000);
ReportBack("I'm still working");
Thread.Sleep(1000);
ReportBack("I'm done");
}
private void ReportBack(string p) {
if (this.InvokeRequired) {
this.Invoke(new Action<string>(ReportBack), new object[] { p });
return;
}
this.Text = p;
}
It is best to dispatch the work but if you must, maybe something like this. Just call this method to wait for the signal rather than calling the waitone.
private static TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(-1);
private const Int32 MAX_WAIT = 100;
public static bool Wait(WaitHandle handle, TimeSpan timeout)
{
Int32 expireTicks;
bool signaled;
Int32 waitTime;
bool exitLoop;
// guard the inputs
if (handle == null) {
throw new ArgumentNullException("handle");
}
else if ((handle.SafeWaitHandle.IsClosed)) {
throw new ArgumentException("closed wait handle", "handle");
}
else if ((handle.SafeWaitHandle.IsInvalid)) {
throw new ArgumentException("invalid wait handle", "handle");
}
else if ((timeout < InfiniteTimeout)) {
throw new ArgumentException("invalid timeout <-1", "timeout");
}
// wait for the signal
expireTicks = (int)Environment.TickCount + timeout.TotalMilliseconds;
do {
if (timeout.Equals(InfiniteTimeout)) {
waitTime = MAX_WAIT;
}
else {
waitTime = (expireTicks - Environment.TickCount);
if (waitTime <= 0) {
exitLoop = true;
waitTime = 0;
}
else if (waitTime > MAX_WAIT) {
waitTime = MAX_WAIT;
}
}
if ((handle.SafeWaitHandle.IsClosed)) {
exitLoop = true;
}
else if (handle.WaitOne(waitTime, false)) {
exitLoop = true;
signaled = true;
}
else {
if (Application.MessageLoop) {
Application.DoEvents();
}
else {
Thread.Sleep(1);
}
}
}
while (!exitLoop);
return signaled;
}
I went with something I haven't seen posted yet which is to use MessageQueues.
The MainThread blocks while waiting for the next message on a queue.
The background thread posts different types of messages to the MessageQueue.
Some of the message types signal the MainThread to update UI elements.
Of course, there is a message to tell the MainThread to stop blocking and waiting for messages.
Seems over the top considering the windows message loop already exists somewhere, but it works.