1

I have this xaml

<Window x:Class="TestCloseWindow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="500" Height="400">
<StackPanel>
    <TextBlock x:Name="Seconds"></TextBlock>
    <Button Content="fasdfd" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Window>

And this code

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
         await CountToTen();
    }

    private Task CountToTen()
    {
       return Task.Factory.StartNew
              (() =>
                  {
                      for (var i = 1; i <= 10; i++)
                      {
                        Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
                        Task.Delay(1000).Wait();
                      }
                   }
                   , CancellationToken.None
                   , TaskCreationOptions.None
                   , TaskScheduler.FromCurrentSynchronizationContext()
              );
    }
}

In this code I use TaskScheduler.FromCurrentSynchronizationContext() in order to access UI from background Task.
I expected that I can see how program count to ten, but instead of it I see blocked UI for 10 seconds and after 10 in TextBlock

How can I fix it?

2 Answers 2

2

You are using a blocking call Wait in your CountToTen function. To fix this you will need to use await instead. Which requires some other changes as well.

async private Task CountToTen()
{
    await Task.Factory.StartNew( async () =>
        {
            for (var i = 1; i <= 10; i++)
            {
                Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
                //Task.Delay(1000).Wait();
                await Task.Delay(1000);
            }
        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
Sign up to request clarification or add additional context in comments.

4 Comments

Got compile error. But it doesn't matter when I use this code without TaskScheduler.FromCurrentSynchronizationContext() (and delete Seconds.Text = ...) all works good
Error 2 The 'await' operator can only be used within an async lambda expression. Consider marking this lambda expression with the 'async' modifier. D:\TestProjects\TestCloseWindow\TestCloseWindow\MainWindow.xaml.cs 33 21 TestCloseWindow
@takayoshi - sorry. take a look now.
@chuex There's no need for the new task at all; it's just unneeded code bloat.
0

By using StartNew with TaskScheduler.FromCurrentSynchronizationContext(), in this particular case, you're not really doing anything at all. Since the entire task will be run in the UI thread it's no different from just executing it right there in line.

The primary source of your problem is Task.Delay(1000).Wait();. You're doing a blocking wait for a second, and you're doing that from the UI thread. You can refactor the code to not do a blocking wait, and also remove the needless task creation. This is all you need:

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    for (var i = 1; i <= 10; i++)
    {
        Seconds.Text = i.ToString(CultureInfo.InvariantCulture);
        await Task.Delay(1000)
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.