2

I have a Windows Form with a status bar which shows the current state of application. I have a class named AppState with update the Label in the status bar and in dispose it changes the state back to "Ready".

In code when I do an operation like:

using (AppState state = new AppState("Processing..."))
{
     //Do some work that take some seconds
}

But the label remains the same. I am not getting any exceptions. The label text is updated but on UI it keeps on showing previous value. Am I missing anything here?

santosc you are right, thats the only thing I am doing. Here is the AppState code

public class AppState : IDisposable
{
    static string Default = "Ready";

    public AppState(string status)
    {
        Form.StatusLabel.Text = status;
    }

    public void Dispose()
    {
        Form.StatusLabel.Text = Default;
    }
}
ata
  • 8,853
  • 8
  • 42
  • 68

6 Answers6

5

It's always the same thing...

If you want to start something that takes a while, don't do it within your GUI thread or your GUI will freeze (no updates of label, no resizing, no moving, no whatever).

Filling your code on thousand places with Application.DoEvents() is also a bad practice.

If you have some long running task (long means > 1 sec) you should probably use a BackgroundWorker. Maybe it's a little bit harder at the beginning, but you will love it if your program gets more complex. Due to the fact, that this has already being discussed several time, here is a link with some sample code.

Now that you know the right tool (BackgroundWorker) to solve your problem, you should get it to work (or ask another question about your new specific problem).

Community
  • 1
  • 1
Oliver
  • 43,366
  • 8
  • 94
  • 151
  • @cornerback84: At first, there can always be only one answer be marked as correct. Second, maybe the two others gave a good direction, but i think my two links will give you a good map about how to do this kind of stuff. Last but not least, it's the one who asks a question to judge about what he thinks is *correct*, any other can just upvote whatever he likes. – Oliver Jan 04 '10 at 09:36
4

Looks like you want to put Application.DoEvents() after setting the StatusLabel text field value. This tells Windows Forms to process the Windows event queue for your form, causing changes to be repainted.

Jeremy McGee
  • 24,842
  • 10
  • 63
  • 95
  • 2
    @winSharp93 - I think that depends on your application. Spawning a new thread in a BackgroundWorker requires the class you're calling to be threadsafe and is rather more complicated than adding one method call. It may also be necessary to design the application to prevent some options being chosen depending on what the BackgroundWorker is up to. Not trivial. – Jeremy McGee Dec 17 '09 at 13:33
  • I do not agree - Application.DoEvents only cares about the effects, not about the reasons. – Matthias Dec 17 '09 at 18:40
2

in order to be "thread safe" use Invoke, and test with the InvokeRequired in the form like:

    // code outside the myForm:-----------------------
    if (myForm.InvokeRequired)
        myForm.Invoke(new ChangeLabelEventHandler(ChangeLabel), "teeeest");
    else
        myForm.ChangeLabel("teeeest");


    // code in the myForm:-----------------------------
    public delegate void ChangeLabelEventHandler(string newText);

    private void ChangeLabel(string newLabelText)
    {
        this.label1.Text = newLabelText;
    }
serhio
  • 28,010
  • 62
  • 221
  • 374
  • Yes, this should work just fine. But - the thread safety is only between the new BackgroundWorker thread and the UI thread. It doesn't stop the user pressing the "go" button (or menu choice or whathaveyou) to kick off /another/ BackgroundWorker at the same time. That may have unexpected consequences. – Jeremy McGee Dec 17 '09 at 20:06
  • To prevent this you can just check the BackgroundWorker.IsBusy to see if there is a currently running job. – Oliver Dec 18 '09 at 08:27
  • In my example, I believe, there is **any need of backgroundWorker**. – serhio Dec 18 '09 at 09:22
2

I'm new to C# stuff, but why can't you just do something like:

private void updateStatusBar(string status)
{
    if (StatusLabel.InvokeRequired)
    {
        StatusLabel.Invoke((MethodInvoker)(() =>
                   {
                       StatusLabel.Text = status;
                   }));
    }
    else
    {
         StatusLabel.Text = status;
    }
}

When you want to update the status?

mrduclaw
  • 3,965
  • 4
  • 36
  • 37
0

Maybe multiple threads could solve your problem.

The easiest way is using a BackgroundWorker.

The reason is that the UI is only able to redraw when the UI thread has nothing else to do. And you are blocking it with your calculation.

Matthias
  • 12,053
  • 4
  • 49
  • 91
  • You would need it when using multiple threads so it's part of the solution. However, without threads it does not change anything. – Matthias Dec 17 '09 at 18:47
0

use Label.Refresh(); it saves a lot of time.This should work for u

user3389579
  • 291
  • 2
  • 4