2

I have AuthenticateWindow and MainWindow, markup and code is exposed below. It is very simplified. When in the MainWindow constructor I use Thread class it works fine, but if I use Task class, UI is suspended, that is 'MainWindow' is not shown while Thread.Sleep(5000); is elapsed. Is it possible to use Task class (because I need its cancellation mechanism and Status property) without any UI suspending?

Important condition: I cannot fix code in AuthWindow.

AuthenticateWindow:

xaml

<Grid>
    <Button Content="OpenMainWindow"
            Click="ButtonBase_OnClick"></Button>
</Grid>

c#

public partial class AuthWindow : Window
{
    public AuthWindow()
    {
        InitializeComponent();
    }

    private void DoAbsolutelyNothing()
    {

    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(DoAbsolutelyNothing).ContinueWith(t =>
        {
            var window = new MainWindow();
            if (window.IsInitialized)
                window.Show();

            Close();
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

MainWindow:

xaml

<Grid>
    <TextBlock Text="MainWindow"></TextBlock>
</Grid>

c#

public partial class MainWindow : Window
{
    private Task _task;

    private void TestMethod()
    {
        Thread.Sleep(5000);
        Debug.WriteLine("TestMethod comleted");
    }

    public MainWindow()
    {
        InitializeComponent();

        // it works badly  
        //_task = Task.Factory.StartNew(TestMethod);

        // it works fine
        new Thread(TestMethod).Start();
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {

    }
}

Windows 7, .Net 4.0

Important: Exposed code reproduces the problem, just copy-paste!

daniele3004
  • 13,072
  • 12
  • 67
  • 75
monstr
  • 1,680
  • 1
  • 25
  • 44

2 Answers2

3

You must force the task to run on another thread

Task.Factory.StartNew(TestMethod, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);

More here:
Why Starting A New Task In The Task Parallel Library (TPL) Doesn’t Always Start A New Thread

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
George Vovos
  • 7,563
  • 2
  • 22
  • 45
  • It works, but I thought `Task` instance runs ALWAYS in another thread by default, doesn't it? – monstr Sep 09 '14 at 13:09
  • I was under the impression that a task started using the default scheduler would always lease a ThreadPoor thread. This is very strange indeed. – Gusdor Sep 09 '14 at 13:28
  • That is correct.But this task was not started using the default scheduler.Check this http://stackoverflow.com/questions/6800705/why-is-taskscheduler-current-the-default-taskscheduler – George Vovos Sep 09 '14 at 13:46
  • Task by default runs in another thread, in your case you forced it to still work on UI thread by using TaskScheduler.FromCurrentSynchronizationContext(). What would be diffrence between synchronous method and Task if it did not run in background? Normally you use Task.Factory.StartNew(MyMethod), no need to use all this options as in accepted answear. – Maximus Sep 09 '14 at 15:24
  • @Maximus You cannot guarantee that the task will run on another thread.(This is guaranteed if you use Task.Run ) http://stackoverflow.com/questions/12245935/is-task-factory-startnew-guaranteed-to-use-another-thread-than-the-calling-thr – George Vovos Sep 09 '14 at 16:39
1

TaskScheduler.FromCurrentSynchronizationContext() creates Task not on ThreadPool Synchronization Context but on Context it is called from, in this case from UI that is why it is frozen.

Maximus
  • 3,458
  • 3
  • 16
  • 27
  • And what should I do? I cannot reject TaskScheduler.FromCurrentSynchronizationContext() – monstr Sep 09 '14 at 12:41
  • Once you get rid of this it will kick of working properly. Even though you create Task it still runs synchronously on UI thread. – Maximus Sep 09 '14 at 12:43
  • But then won't the code that creates the new `MainWindow` instance throw an exception as it will not be running on the UI thread? – Daniel Kelley Sep 09 '14 at 12:46
  • @DanielKelley You can use the Dispatcher Object to update the UI thread http://stackoverflow.com/questions/9602567/how-to-update-ui-from-another-thread-running-in-another-class – George Vovos Sep 09 '14 at 12:49
  • If you create new Window there is no need to mess around with Tasks since you have to do this on UI thread. – Maximus Sep 09 '14 at 12:51
  • I was going to post this answer but was pretty sure that the `DispatcherSynchronizationContext` would run the method synchronously. Perhaps I was wrong. Is the call to `Window.Show` modal? – Gusdor Sep 09 '14 at 12:53
  • I cannot reject `TaskScheduler.FromCurrentSynchronizationContext()` because of this :( http://stackoverflow.com/questions/23934236/wpf-asynchronous-taskt-blocking-ui – monstr Sep 09 '14 at 12:53
  • @Gusdor, it is not modal, `ShowDialog` is modal – monstr Sep 09 '14 at 12:54
  • @GeorgeVovos I'm well aware of that. The point was as it stands the answer is only half complete. You can't say "don't do Y" when that also requires "you need to do Z" without mentioning it. – Daniel Kelley Sep 09 '14 at 13:51