I\'ve got a c# windows form app I threw together. It\'s fairly simple:\\
inputs:
If you use a background worker you can use the ReportProgress method to return any integer, such as the number of records processed. It doesn't have to be a percentage. Then, in the ProgressChanged handler you can update your textbox. E.g.
int count = e.ProgressPercentage;
textBox1.Text = string.Format("{0} images processed.", count);
If you don't want to use a background worker you can call Application.DoEvents() inside your loop. This will give the UI an opportunity to refresh itself and respond to user actions. But beware - it will slow your program a lot so you may want to call it only on every 100th iteration.
You are on the right track with the background worker. Here is an example I put together to show you how to do this. Create a new windows app with Form1. Add 4 controls to it: label1, backgroundWorker1, button1, and button2. Then use this code-behind. Then you can use the ReportProgress userState to report back to the main thread whatever you want. In this example, I am passing a string. The ProgressChanged event handler is then on the UI thread, and updates the textbox.
public partial class Form1 : Form
{
int backgroundInt;
public Form1()
{
InitializeComponent();
backgroundWorker1.WorkerReportsProgress = true;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = e.UserState as string;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundInt = 1;
while (backgroundWorker1.CancellationPending == false)
{
System.Threading.Thread.Sleep(500);
backgroundWorker1.ReportProgress(0,
String.Format("I found file # {0}!", backgroundInt));
backgroundInt++;
}
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
}
Just create a (1) a delegate to wrap your ProcessImages method call, (2) fire off the call using a delegate, and (3) when you wish to update the textbox from your ProcessImages method, check for cross-thead operation and make sure you do the update from the main thread:
delegate void ProcessImagesDelegate(string did, string sourceFolder, string destFolder, string strNumImages);
private void ProcessImages(string DID, string SourceFolder, string DestFolder, string strNumImages)
{
// do work
// update textbox in form
if (this.textBox1.InvokeRequired)
{
this.textBox1.Invoke(new MethodInvoker(delegate() { this.textBox1.Text = "delegate update"; }));
}
else
{
this.textBox1.Text = "regular update";
}
// do some more work
}
public void MyMethod()
{
new ProcessImagesDelegate(ProcessImages).BeginInvoke(tbDID.Text, tbSource.Text, tbDest.Text, comboBoxNumberImages.SelectedItem.ToString(), null, null);
}
The UI doesn't update because you're not allowing any window messages to be processed in your long-running file processing loop. WinForms apps redraw in response to WM_PAINT messages which are processed in the message queue in the main thread.
The simplest solution is to force a UI update: Try calling Update() on your form after modifying the textbox inside your loop.
Your app will still be UI frozen (non responsive to mouse clicks, etc) but this should at least get the progress messages drawn on the screen. If updating the display is all you really need, then stop here.
The next level of solution would be to allow your application to process pending window messages in your file processing loop. Call Application.DoEvents() in your loop (Instead of form.Update). This will allow the form to redraw itself with your text output updates and will eliminate your UI freeze - the app can respond to mouse and keyboard activity.
Be careful here, though - the user could click the button that started the current activity while the current activity is in progress - reentrancy. You should at a minimum disable the menu or button that kicks off your long-running file processing to prevent reentrancy.
A third level of solution would be to use a background thread for the file processing. This introduces a whole host of new issues you need to be aware of, and in many cases threads are overkill. There's not much point in pushing the file processing off into a background thread if you're not going to allow the user to do anything else with your app while the file processing is happening.
I did not have to create a background worker. All I did was called .Update()
followed by System.Threading.Thread.Sleep(100)
and it started working.