40

What is the best way to update a label on a Windows Forms application while processing?

I have a loop that does some processing to files on the user's system when the user clicks a button.

foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
{
   // Do processing
   // Show progress bar
   // Update Label on Form, "f.Name is done processing, now processing..."
}

What would be some sample code?

What exactly is this called? Is it threading or delegates?

default locale
  • 13,035
  • 13
  • 56
  • 62
Picflight
  • 3,832
  • 13
  • 61
  • 90

5 Answers5

76

A quick fix for you would be:

Label1.Text = f.Name + " is done processing, now processing...";
Label1.Refresh();

You really want to avoid DoEvents, otherwise you'll have problems if your user repeatedly presses buttons on your form.

casperOne
  • 73,706
  • 19
  • 184
  • 253
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120
14

You should be doing this on another thread, and then updating your UI thread from that thread. You are blocking further processing by performing this work on the UI thread.

If you can't move this code to the UI thread, then you could always call Application.DoEvents, but I strongly suggest you explore these options first:

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • 1
    I agree with this - especially for BackgroundWorker. I use it frequently myself. BackgroundWorkers make multi-threading operations like this simple and easy! – Keithius Feb 21 '09 at 16:45
13

You'll need to get your data from one thread to the other. This can be done in a couple of ways...

First, your "background" thread could update some kind of "CurrentStatus" string variable that it changes as it goes along. You could then put a timer on your form that would then grab the CurrentStatus variable and update the label with it.

Second, you could simply invoke the operation from the background thread to the UI thread with a delegate using the InvokeRequired property of the label control. So for example...

private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
    if (this.label1.InvokeRequired)
    {
        this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
        return;
    }

    this.label1.Text = status;
}

You can call that UpdateStatus() method from any thread (UI or background), and it will detect whether or not it needs to invoke the operation on the main UI thread (and if so, does it).

To actually set up the thread, you can do so like this:

    private void StartProcessing()
    {
        System.Threading.Thread procThread = new System.Threading.Thread(this.Process);

        procThread.Start();
    }

    private void Process() // This is the actual method of the thread
    {
        foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
        {
            // Do processing
            // Show progress bar
            // Update Label on Form, "f.Name is done processing, now processing..."
            UpdateStatus("Processing " + f.Name + "...");                
        }
    }

Then when the user clicks the "GO" button you'll simply call StartProcessing().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brandon
  • 13,956
  • 16
  • 72
  • 114
1

If your processing is lengthy do it in a backgroundworker thread.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

devSpeed
  • 488
  • 2
  • 10
0

I also recommend to use :

Application.DoEvents();

Processes all Windows messages currently in the message queue.