0

Im having some trouble with a ToolStripStatusLabel in Winforms application. To better explain i have some code here

bottomLbl.Text = "Adding file(s) to list...";
this.Text = "Adding file(s) to list...";

listAllFiles(carrier, type, chkListBox, withDestSystem, listBox, cmbBox);

bottomLbl.Text = "Done!";
this.Text = "Done";

What i dont get is, that this.Text does change to "Adding files.." but not bottomLbl even though i set it to do so before this.text. Both controls get the "Done!" text after the listAllFiles function has been run.

But is there something special i have to do on a ToolStripStatusLabel ?

Daniel Jørgensen
  • 1,183
  • 2
  • 19
  • 42
  • Understanding when UI updates occur is very, very important. It cannot happen when your UI thread is off in the woods, listing files. Your UI is not responsive either, clicks don't work. Add `bottomLbl.Update();` for a quick fix. Something like BackgroundWorker is a real fix. – Hans Passant Oct 19 '14 at 03:56

2 Answers2

1

You need to refresh the form before calling the function

bottomLbl.Text = "Adding file(s) to list...";
this.Text = "Adding file(s) to list...";
this.Refresh();

listAllFiles(carrier, type, chkListBox, withDestSystem, listBox, cmbBox);

bottomLbl.Text = "Done!";
this.Text = "Done";
  • Thanks! I just dont quite get why this is necessary the first time at (adding files) and not at (done), and also why this.text updates without refreshing, whereas bottomLbl.Text doesnt update. But it sure works by refreshing! – Daniel Jørgensen Oct 19 '14 at 07:59
  • @DanielJørgensen Every time you call *bottomLbl.Text* is like sending a *paint* message via *invalidate*. But paint messages are in the bottom of the hierarchy list of messages. That means that even if you send 20 paint messages in a single function call(which is a response to another message eg button click) only one is processed(the last) at the end of the function. For more information search *invalidate vs refresh* – γηράσκω δ' αεί πολλά διδασκόμε Oct 19 '14 at 08:42
  • @DanielJørgensen Now, the fact that *this.Text* has an immediate effect is something i didn't know. Maybe the system does send a paint message and place it in the beggining of list of messages to be processed, just like *refresh*, but only for the parent form. – γηράσκω δ' αεί πολλά διδασκόμε Oct 19 '14 at 08:46
0

It looks to me like you're setting up a condition where we can't reliably predict which of the UI updates will be displayed to the screen before the final UI updates get displayed.

You're doing some UI updates (e.g. label1.Text = ...) before performing a time-consuming process (listAllFiles()). After that completes, you're doing some more (final) UI updates.

One or more of the "early" UI updates gets queued to be displayed as soon as the main thread (the UI thread) has some time to refresh the window.

What we don't necessarily know is which types of controls (ToolStripStatusLabel versus Label, for instance) internally consider the setting of their Text property to be something that can't wait to be displayed.

It sort of sounds like one of those types will allow its Text property to be updated without waiting until it gets displayed (that's a non-blocking call) while the other type will ensure that the change gets displayed before proceeding (that's a blocking call).

Even if you determine what their behavior is through testing, it could change in the future or in different environments.

Optionally, you could customize one or more of those types to specify whether to block or not. You could do this by either calling Refresh() or Invalidate(). But I recommend an alternative approach:

Keep the load of tasks performed in the UI thread to a minimum. This way, the UI is more responsive to the user and you can have more confidence that your UI updates will be displayed quickly.

Generally, this means we should perform all time-consuming work in a different thread, asynchronously, and we can update the UI with the status of that work as frequently as we like. To accomplish this, I recommend looking into the BackgroundWorker type. Its purpose is to perform time-consuming work asynchronously while maintaining a responsive UI.