简体   繁体   中英

TaskScheduler.FromCurrentSynchronizationContext block ui

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?

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());
}

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)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM