-3

I have tried to find out the answer but no real answer found. Can anyone answer following? I am trying to update status in the parent window by calling Dispatcher Method, but I see it does not update the status in sequential manner. I see the status update in the mainwindow as follow:

First process started... First Process done! Third Process done!

Instead of delay between the UpdateStatus, there can be some other method or task. So, Why it does not update other status? Any real answer please?

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        UpdateStatus("First Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("First Process done!");

        Thread.Sleep(5000); //or any method

        UpdateStatus("Second Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("Second Process done!");

        Thread.Sleep(5000); //or any method

        UpdateStatus("Third Process started...");
        Thread.Sleep(5000); //or any method
        UpdateStatus("Third Process done!");
    }

    private void UpdateStatus(string message)
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate
        {
            MainWindow.main.lblTest.Content = message;
        }
        ));
    }
biplabks
  • 5
  • 1
  • 4

3 Answers3

0

A single thread can't both update the UI and sleep at the same time.

You could wait asynchronously between the status updates though:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    UpdateStatus("First Process started...");
    await Task.Delay(5000);
    UpdateStatus("First Process done!");

    await Task.Delay(5000);

    UpdateStatus("Second Process started...");
    await Task.Delay(5000);
    UpdateStatus("Second Process done!");

    await Task.Delay(5000);

    UpdateStatus("Third Process started...");
    await Task.Delay(5000);
    UpdateStatus("Third Process done!");
}

private void UpdateStatus(string message)
{
    MainWindow.main.lblTest.Content = message;
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thanks for your comment. However, if there is any method instead of delay, how it will work? – biplabks Sep 27 '17 at 15:35
  • Then you need to actually perform some long-running work on a background thread. Otherwise the "Third Process done!" status will indeed be displayed immediately. – mm8 Sep 27 '17 at 15:36
  • If the method takes 1 or 2 minutes, the status change can be viewed easily. How can I block that time so that status can not be updated instantly? – biplabks Sep 27 '17 at 15:56
  • But I don't know how long my method will run. If I give task delay for 50 seconds, and method runs for 110 seconds, then it might not work. I guess. – biplabks Sep 27 '17 at 16:14
  • What method are you talking about here? You didn't mention any in your original question. As mentioned, please ask a new question if you have another issue. – mm8 Sep 27 '17 at 16:17
0

I hope this will make it more clear.

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        // I run on the main thread and return immediately
        await SearchForAliensAsync();
    }

    private async Task SearchForAliensAsync()
    {
        // I run on (capture) the caller thread (main thread)
        UpdateStatus("Searching for aliens...");

        /* Dispatch the dirty work on a background thread and return immediately,
         * so that the caller thread (main thread) remains responsive.
         * If you don't do that, the main thread will get blocked.
         * From the user perspective the UI is frozen.
         * The main thread will search infinitely for aliens,
         * instead of doing its main job - poping and dispatching messages from
         * its message queue (Win32 is event driven).
         * The operating system will keep notifying the main thread,
         * that the user has clicked on the window or smashed multiple keys on the keyboard,
         * but the main thread won't listen, it's searching for aliens!
         * The operating system monitors all main threads, by measuring what
         * time has elapsed from the last call to GetMessage(...) and
         * if the latter exceeds a certain amount, it will play a trick on you.
         * The OS will create a transparent window and place it on top of the 
         * unresponsive one, so that it can detect the next angry mouse click
         * and display the famous "Application is not responding" dialog...
         */
        await Task.Run(() =>
        {
            // I run synchronously on the thread pool and I won't finish any time soon..
            SearchForAliens();
        });

        // When my time comes, I'll be dispatched on the captured thread (main thread)
        UpdateStatus("Aliens exist!");
    }
shadow32
  • 464
  • 3
  • 9
-1

You are running everything synchronously in UI thread, preventing any invoke until you finish (therefore no updates and then all updates at once). Simply move your code in task:

void Button_Click(object sender, RoutedEventArgs e) => Task.Run(() =>
{
     ... // rest of your code
});

and you should be fine (fine unless you press button twice, but that's easy to fix I guess).

Btw, you can also use another overload of invoke:

Dispatcher.Invoke(() => lblTest.Content = message);
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • Yep. If you indeed want to use sleep, then solution of @mm8 (`async/await`) is better, though I would just use a timer and collection of messages in such case. I have made my solution with synchronous methods in mind, with async methods again - use `async/await` approach. – Sinatr Sep 28 '17 at 07:17