1

UWP application, C#, Visual Studio 2017, Windows 10 Creators Update (10.0; Build 15063).

Let's call TextBlock1 as T1, TextBlock2 as T2... Desired output is:

T1 shows "Work started."

T2 shows "Step 1"

T2 shows "Step 2"

T2 shows ""

T1 shows "Work Finished."

    private async void Btn_Click(object sender, RoutedEventArgs e)
    {
        TextBlock1.Text = "Work started.";
        await DoWork();
        TextBlock1.Text = "Work done.";
    }

    private async Task DoWork()
    {
        TextBlock2.Text = "Step 1";
        await Task.Delay(1); //Pretend to do something
        TextBlock2.Text = "Step 2";
        await Task.Delay(1); //Pretend to do something
        TextBlock2.Text = "";
    }

When I debug, actual output is non-deterministic:

1: TextBlock updates only happen when I step into an await or when the event handler closes.

2: Sometimes TextBlock updates occur at await #1, sometimes at await #2, sometimes at both, and sometimes at neither.

3: Regardless of prior events, T1 will show "Work done." and T2 will show "" at the end of Btn_Click().

When I request a UI update, I want the program to do nothing except what's necessary to perform the update. It should not proceed to my next request before the update is shown on the UI.

I've spent days on this. Is it possible?

I've found a way to remove the non-deterministic aspect of this problem. But I don't really understand what's happening, and it still doesn't meet the requirement in bold above:

    private async Task UpdateTextInUI(TextBlock textBlock, string str)
    {
        await textBlock.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            new DispatchedHandler(() => { textBlock.Text = str; }));
    }
Dpt
  • 29
  • 4
  • 1
    I understand your concern about wanting the program to do what you want, but in order to make that happen, you need to find out how to write code that can only do what you want, and then write that code. If the code does what you don't want, that's because you wrote code that does something you don't want. You are the only one in the equation who has the capacity for choice. "When I request a UI update, I want the program to do..." -- that sounds like you're complaining to the management at a hotel. Programming isn't like that. – 15ee8f99-57ff-4f92-890c-b56153 Nov 29 '17 at 16:43
  • 1
    `Task.Delay(1)` is going to wait 1ms. Are your real processes really that short? – Paul Abbott Nov 29 '17 at 16:46
  • @EdPlunkett I'm not sure that I understand. I agree that I'm responsible for writing the program to do what I want. – Dpt Nov 29 '17 at 16:59
  • When you "pretend to do something", what is the real workload here? Is it computationally bound, and does it ever asynchronously yield? – spender Nov 29 '17 at 17:03
  • @PaulAbbott No, they are longer. Keeping in mind that once a UI update is requested, I want nothing to happen until the request is fulfilled... Does that not mean the process duration is irrelevant? – Dpt Nov 29 '17 at 17:10
  • @spender Finally I am at the point where I don't care about that. I just want this extremely basic case to work. I would ask to please help me to comprehend this basic example, and then I can go on my own to build on this foundation. If someone can explain an entirely different way to do what I want, then I will happily change everything and start from scratch using that knowledge. – Dpt Nov 29 '17 at 17:12
  • Is this relevamt : https://stackoverflow.com/questions/15255078/gui-does-not-redraw-while-stepping-in-debug-mode – PaulF Nov 29 '17 at 17:26
  • @PaulF Perhaps!!!!! If that explains what's happening, then I may be in trouble, because I apparently need to learn a lot more to properly debug my application.... How can I be sure of the order of events in my program if I can't check them while I debug? Nevertheless, if that is relevant and stops me from going on a wild goose chase, then you have my sincere gratitude. – Dpt Nov 29 '17 at 17:51
  • @Dpt: Getting an understanding of how your framework works is useful - do control events happen on the same thread as the UI update (there are many questions here about why the progress bar only steps from 0 to 100% even when updates are made in smaller increments). Learning a variety of debugging techniques is always useful - all debugging techniques will have some affect on the operation of all but the most trivial programs. Writing to the console or a file or creating a list of strings in memory can be useful & time-stamping the output to ensure actual order of events. Glad to be of help. – PaulF Nov 30 '17 at 09:37

1 Answers1

0

Let me break it down for you:

  1. TextBlock updates only happen when I step into an await or when the event handler closes.

This is perfectly normal. The await call basicly does the next thing: start the given function, and until that is ongoing return to the callee. This also implies, that when your awaited function returns, the scope immideatly returns to after the await. So, if your awaited function is really quick, then the UI might not have enough time to apply your changes.

  1. Sometimes TextBlock updates occur at await #1, sometimes at await #2, sometimes at both, and sometimes at neither.

Same as the above, sometimes the UI has enough time, sometimes it doesn't. That's the funny thing with threads. They are non-deterministic.

  1. Regardless of prior events, T1 will show "Work done." and T2 will show "" at the end of Btn_Click().

After the DoWork function completes, the UI gains back full control, so it can apply all your changes -> the last Text values get applied.

Edit:

If you really want the UI to update, you can await Task.Yield(). This will force the UI to gain back control.

rokkerboci
  • 1,167
  • 1
  • 7
  • 14