The Scenario
I have a windows forms application containing a MAINFORM with a listbox on it. The MAINFORM also has a THREAD POOL that creates new threads and fires them off to do lots of different bits of processing. Whilst each of these different worker threads is doing its job, I want to report this progress back to my MAINFORM, however, I can't because it requires Cross-Thread communication.
Progress
So far all of the tutorials etc. that I have seen relating to this topic involve custom(ish) threading implementations, whereas I literally have a fairly basic(ish) standard THREAD POOL implementation. Since I don't want to really modify any of my code (since the application runs like a beast with no quarms) - I'm after some advice as to how I can go about doing this cross-thread communication. ALTERNATIVELY - How to implement a different "LOGTOSCREEN" method altogether (obviously still bearing in mind the cross-thread communication thing).
WARNING:
I use this website at work, where we are locked down to IE6 only, and the javascript thus fails, meaning I cannot click accept on any answers during work, and thus my acceptance rate is low. I can't do anything about it I'm afraid, sorry.
EDIT:
I DO NOT HAVE INSTALL RIGHTS ON MY COMPUTER AT WORK.
I do have firefox but the proxy at work fails when using this site on firefox.
And no, funnily enough, I don't have the internet at home, I literally just moved to this city and the flat is a new build, so the address hasn't been registered with the post office, and thus the phone company cannot find the address on their system till they send a surveyor out, smarty pants.
FURTHER EDIT:
I DO NOT WANT TO CHANGE MY THREADING IMPLEMENTATION. AT ALL! - Accept to enable cross-thread communication....why would a backgroundworker help here!?
CODE RELATED EDIT:
Does it make a difference that when my THREAD POOL executes the new threads, it creates a new instance of a class and calls the entire thing on that new thread........i.e. your code example doesn't quite fit....i think?
Use the BackgroundWorker class in .NET and use the ProgressChanged and RunWorkerCompleted events to communicate back to your UI thread
Edit:
Sounds like you don't like BackgroundWorker, or just don't want to refactor. In that case, you have to check the InvokeRequired property on your form or one of your controls and if it is true, then you have to call Control.Invoke to force your UI update logic to occur on your main thread.
here is an example:
private void MyThreadFunction()
{
if (!InvokeRequired)
{
myLabel.Text = "You pushed the button!";
}
else
{
Invoke(new ThreadStart(MyThreadFunction));
}
}
You can use any delegate type to pass to Invoke, because it takes optional parameters that can be passed to your delegate when it is invoked on the main thread.
You could do something like this:
class MyForm : Form
{
private Label label = new Label();
private void DoWork()
{
// Do work ... Not in UI thread
// Update label... In UI thread
this.Invoke(new MethodInvoker(() => label.Text = "New Text!"));
}
}
The DoWork method it's the one running in your worker threads. You could check if an invoke is required using InvokeRequired property, but the assumption is that your code is running on worker threads so the invoke will always be required.
You can do this using delegate object.
So you would create a callback method in your MAIN form and let your CHILD forms call this method using delegates when they are done processing.
Try using Control.BeginInvoke to queue your update to the UI on the UI thread.
Related
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 have an usual C# Windows Forms Application with one Form and several TextBoxes / Labels which runs (how I understand) in its own thread. (Win 7 64 / VS 2008 / Net 2).
Now I want to start a second thread while my base application stays in the first thread.
The second thread shall retrieve some system information and input it into the Labels while my user is still able to fill in the TextBoxes while the information is going to be retrieved by the second thread. So the advantage would be by my understanding, that the user has not to wait until retrieving information is completed and the main application would not hang in that time.
Let's say I want this code to be executed in a second thread which starts in the Form_Shown event:
Label1.Text = GetInternetIP();
try
{
Label2.Text = System.Net.Dns.GetHostEntry(Label1.Text).HostName.ToString();
}
catch{MessageBox.Show("Fatal Error."); Process.Start("shutdown.exe", "-r -t 2"); this.Activate(); SendKeys.Send("%{F4}");}
I would be grateful for a detailed description on how to setup a "new thread". I am a newbie but I would like to learn something new and optimize (speed up) my very first applications.
The Label1 and Label2 are in the main thread on the main form (Form1). So I have to get the retrieved information there.
in dealing with Windows forms the UI can only run on one thread, then it will create background threads the background threads retrieve the data and then pass it to the single UI Thread. This is also how it works in WPF.
take a look here on how to do this
http://msdn.microsoft.com/en-us/magazine/cc300429.aspx
You should never access your UI components from code running on another thread. In fact, you shouldn't access anything from multiple threads unless those things are explicitly thread-safe (or you access them in a thread-safe manner).
In your example you are saying you want to fetch information which takes some time. In your case the programming model you want is to have your main thread call an asynchronous function to retrieve that information, and it should signal your main thread when the information is ready.
There are a lot of different ways to implement multithreaded programming in C#, but here is one example:
public Task<IPAddress> GetInternetIP()
{
return Task.Factory.StartNew(() =>
{
IPAddress ip;
// do some work to get the IPAddress
return ip;
});
}
private void Form_Load(object sender, EventArgs e)
{
GetInternetIP().ContinueWith(ip =>
{
Label1.Text = ip.ToString();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
In this case what you're doing is executing a System.Threading.Tasks.Task which will handle the multithreading for you. And you're telling it to continue execution with a method on the current thread. That method is passed the return value of the task (in this case an IPAddress object).
to access user controls that are on the main thread from your background thread you only need to use BeginInvoke against the controls you want to populate. This is an article that fully explains how to do so along with the ins and outs of doing so.
http://weblogs.asp.net/justin_rogers/pages/126345.aspx
The three answers which I received brought me nowhere or have not worked, so I found it out myself much later: I used the Backgroundworker-Control to achieve what I wanted. In the "Completed"-Event of the Backgroundworker I can access the UI and transfer the information to the form attached to my application. What helps me a second thread if my UI is locked for that second thread, so Backgroundworker is the best for me to go and self-explaining.
Web Developer here and need some advice on how to achieve what must be a common requirement in Windows Forms.
I have a windows client app that calls a business object in a separate project to perform some long running tasks. Difference to other examples is that the process live in another class library i.e. Business.LongRunningTask();
I have a list box in the client that I would like to have logged to by the task. I can run the process on the UI thread passsing in the instance of the textbox and calling Application.DoEvents() when I log to the textbox from within the task. All fine, but not elegant and would prefer not to call Application.DoEvents();
If I run the long running process on a separate thread using delegates I cannot access the textbox or delegates created in the windows client form which rules out BeginInvoke calls.
Surely this is bad design on my part and would appreciate some feedback.
You're looking for the BackgroundWorker class.
To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished.
You can find a complete example here: http://msdn.microsoft.com/en-us/library/b2zk6580(v=VS.100).aspx#Y1351
I can run the process on the UI thread
passsing in the instance of the
textbox and calling
Application.DoEvents() when I log to
the textbox from within the task.
Yes, you could also pass in an instance of ILoggingINnterface that you have used to put in the code to write to the text box FROM WITHIN THE UI and thus have taken care of all the nice BginInvoke stuff ;)
If I run the long running process on a
separate thread using delegates I
cannot access the textbox or delegates
created in the windows client form
which rules out BeginInvoke calls.
Ah. No. You just most invoke back to the dispatcher thread then you can access all the UI elemente you like.
Yeah, avoid Application.DoEvents().
To marshall the call back onto the UI thread, call this.Invoke(YourDelegate)
To access UI elements from a different thread, you can use control.Invoke to call a delegate on the owning thread.
I used this at one point to create a live log screen which was updated from a timer while a different worker thread was running. Heres a simplified version:
public class DifferentClassLibrary
{
public delegate void StringDataDelegate(string data);
public event StringDataDelegate UpdatedData;
public void DoStuff()
{
if (UpdatedData != null)
{
Thread.Sleep(10000);
UpdatedData("data");
}
}
}
And in the winform:
public void UpdateTextBoxCallback(string data)
{
if (uiTextBoxLiveLogView.InvokeRequired)
{
uiTextBoxLiveLogView.Invoke(new DifferentClassLibrary.StringDataDelegate(UpdateTextBoxCallback), data);
}
else
{
uiTextBoxLiveLogView.Text += data;
}
}
void Main()
{
DifferentClassLibrary test = new DifferentClassLibrary();
test.UpdatedData += UpdateTextBoxCallback;
Thread thread = new Thread(new ThreadStart(test.DoStuff));
thread.Start();
}
In my application i am sending emails of bigger size (> 2.5 Mb). Now till the emails are being sent, the application is in hanged up state (mouse cursor is of busy state).
One of my friend suggested to use background worker that "could" display message something like "Please wait...Sending email". I have no idea as to how to use the background worker process. Please guide me
Or, if there is any other quicker/easier alternative, i would appreciate the inputs
You don't want to use a separate process - you want to use a different thread.
The work of sending the email shouldn't be done in the UI thread, as that will prevent it from updating. However, you may want to disable parts of your UI while the email is being sent, depending on your app.
When it comes to doing the email work in the background, you could create a new thread explicitly, use the thread pool, or create a BackgroundWorker. You probably want to use Control.Invoke or Control.BeginInvoke to marshal a delegate invocation back to the UI thread when the email has been sent. Personally I would probably use a thread directly for this - it sounds like it'll take a reasonable time, and my guess is that you won't be able to report meaningful progress (which is the main task that BackgroundWorker makes easy). EDIT: As per comments, BackgroundWorker also marshals exceptions to the UI thread, which you may find useful.
So something like:
public void SendEmailButtonClicked(object sender, EventArgs e)
{
// Make any changes to the UI here to disable whatever you want
new Thread(SendEmail).Start();
}
private void SendEmail()
{
// Do the sending of the email here (this is in the non-UI thread)
// Then afterwards, possibly in a finally block
Action action = EmailSent;
this.BeginInvoke(action);
}
private void EmailSent()
{
// Back in the UI thread, do whatever you need to indicate
// success/failure, re-enable disabled parts of the UI etc
}
The BackgroundWorker documentation contains some pretty good examples which should help to get you started.
A background worker is perfect for this. It allows you to monitor progress quite easily and can Marshall back to the UI thread easier than a standard thread. Some links after some google fu:
http://justins-fat-tire.blogspot.com/2010/05/c-using-background-worker.html
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
http://www.dotnetperls.com/backgroundworker
If you don't want your UI to hang while waiting for long processes you have to use a thread. BackgroundWorker is a good implementation of this that provides hooks for you to use to report progress, allow the user to abort the process etc.
There are plenty of questions about the BackgroundWorker here on Stack Overflow or check the MSDN documentation.
I would try to use BackgroundWorker control. Refer below links
Designing an Interface for BackgroundWorker
http://www.albahari.com/threading/part3.aspx
http://www.agiledeveloper.com/articles/BackgroundWorker.pdf
Look at this threading tutorial:
http://msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx
Basic idea is to have your mouse click event spawn a new thread that will take care of sending the email.
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.