0

On a WPF form I need two status messages in a text field while the program does some lengthy task: "Started" and "Finished" to keep it simple. The message is shown in a textblock bound to a property with OnPropertyChange in the setter of course.

Problem: Only the second message is shown when I change this property.

StatusMessage = "Started";
Thread.Sleep(700); // Searching the harddrives and make some lists in the real prog. 
StatusMessage = "Finished";

Strange for me: If I place a MessageBox.Show between first change of property and the Sleep - which doesn't make sense of course - everything works fine:

StatusMessage  "Started";
MessageBox.Show("Just click");
Thread.Sleep(700);
StatusMessage  "Finished";

Trying to achieve the same with a message window shows nearly same behavior: The new window opens but isn't filled with content - unless a put a senseless MessageBox.Show into the code. (I guess this has the same root cause so add this in the thread here.)

MsgWindow mw = new MsgWindow();
mw.Show();
MessageBox.Show("Just click"); //If I delete this line the window opens without content, color etc.
Thread.Sleep(700);
mw.Close();

Where is my mistake?

dymanoid
  • 14,771
  • 4
  • 36
  • 64

1 Answers1

1

In your example the issue is the call to Thread.Sleep - as per msdn, this does the following:

Suspends the current thread for the specified amount of time.

The current thread is the UI thread, which needs to be free for the Binding Engine to update and show your Started text. However immediately after calling OnPropertyChanged the UI thread is suspended - and only becomes free after you've changed the text to Finished.

This will be the same in your real-life case - your work is being done synchronously on the UI thread, so the UI thread isn't free to update the UI.

async/await is your friend here - the following example code should work as you expect

StatusMessage = "Started";
await Task.Delay(700);
StatusMessage = "Finished";

In the real-life case, you should ideally be able model your long-running process in an async manner to do something like

StatusMessage = "Started";
await DoSomeAsyncWork();
StatusMessage = "Finished";

Or if your work has to be synchronous it can be wrapped in a Task as follows:

StatusMessage = "Started";
await Task.Run(() => DoSomeWork());
StatusMessage = "Finished";

I'd recommend this Best Practices in Asynchronous Programming msdn magazine article for some pointers on how to use async correctly.

Jeremy Crick
  • 108
  • 3