I have a task which, when completed, is supposed to continue with another task that shows a winform (the winform was previously initialised on the UI thread, so it does have a handle).
private static Task RunningTask
{
get;
set;
}
public static UpdaterTool.Forms.UpdateResult UpdateResultForm;
private void DoWork()
{
UpdateResultForm = new Forms.UpdateResult();
//the next line forces the creation of the handle -
//otherwise InvokeRequired will later on return false.
var hackHandle = UpdateResultForm.Handle;
var ctx = TaskScheduler.FromCurrentSynchronizationContext();
RunningTask = Task.Factory.StartNew(() => DownloadAndInstallFiles(), CancelTokenSource.Token)
.ContinueWith(_ => WorkComplete(), CancelTokenSource.Token, TaskContinuationOptions.NotOnFaulted, ctx);
}
private void WorkComplete()
{
ShowResultForm();
}
private void ShowResultForm()
{
if (UpdateResultForm.InvokeRequired)
{
try
{
UpdateResultForm.Invoke(new MethodInvoker(ShowResultForm));
}
catch { }
return;
}
UpdateResultForm.Show();
}
The problem is that no matter what combination of overloads for the ContinueWith() I use, the UpdateResultForm is either not shown at all(meaning the continuation does not happen, the worker hangs at "running"), or when it is, it hangs the UI, like its expecting the worker thread to finish or something. I dont understand why this happens when I tried to show it on the UI thread, by using FromCurrentSynchronizationContext().
In my understanding, inside the DoWork method I start on the UI thread (which is why I initialise the form there). When the code enters Task.Factory.StartNew, it switches to the working thread. When it completes, it continues with WorkComplete which just shows the previously initialised form, on the UI thread.
What am I missing? Thanks,
Using InvokeRequired is a strong anti-pattern. It's not that common to have no idea on what thread a method runs. That's the case here as well, you already used TaskScheduler.FromCurrentSynchronizationContext() so you know that the task runs on the UI thread. There's no point in checking again. Which also eliminates the need to create the form handle early.
The kind of problems you are having can be caused by running DoWork() from a worker thread. Maybe you called it from a task as well. Which makes FromCurrentSynchronizationContext() return the wrong context. And will display the form on a thread that doesn't pump a message loop, it will be dead as a doornail. Or by blocking the UI thread, waiting for the task to finish. That will always cause deadlock, the task cannot complete unless the UI thread goes idle and can execute the ShowResultForm() method.