-1

I'm running a Task in a new thread and want to wait for it to finish.

var a = "logic before the task starts";
await Task.Factory.StartNew(() => MyHugeFunction(_token), _token);
var b = "logic after the task is finished";

It worked perfectly until I started to dispatch inside of the thread with:

 await Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
 {
    SomeLogic();
 }));

The task itself works, but the await for my running task isn't working anymore. As soon as I am dispatching in the thread, the var b will be assigned in the main thread.

I already have some workarounds but I just wondered if I'm doing something stupid or this is caused by other circumstances

I'm working with C# 8.0 and .Net Framework 4.7.2.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
  • BeginInvoke returns immediately after passing the Action to the dispatcher queue. It is unclear what you are trying to do here. Perhaps use Invoke instead of BeginInvoke. – Clemens Jan 19 '22 at 18:11
  • From an exception-handling perspective, prefer `Dispatcher.InvokeAsync` to `Dispatcher.BeginInvoke` – Joe Jan 19 '22 at 18:17
  • @Clemens thank you! Invoke instead of BeginInvoke fixed it for me. – Thomas Kreidl Jan 19 '22 at 18:24
  • @Joe Dispatcher.InvokeAsync causes the same problem. Just Invoke did it for me. But thanks :) – Thomas Kreidl Jan 19 '22 at 18:29
  • 1
    The comment by Joe was not meant to solve your problem, but just to tell that *in case* you want to make an asynchronous Dispatcher invokation, InvokeAsync is better suited than BeginInvoke. – Clemens Jan 19 '22 at 19:52

1 Answers1

3

I'm running a Task in a new thread and want to wait for it to finish.

You want to use Task.Run instead of StartNew for that. StartNew is a dangerous, low-level API that should almost never be used, and in the few cases where you should use it, you should always pass a TaskScheduler.

await Application.Current.Dispatcher.BeginInvoke(new Action(async () =>

Imma stop you right there. First, you're explicitly creating an Action delegate with async, which results in an async void method, which should be avoided. Next, using Dispatcher to do any kind of Invoke or BeginInvoke really shouldn't be done at all.

Instead, use the Progress<T> type. This keeps your logic in your background thread, which can pass objects as updates to the UI thread, and the UI thread decides how to display those progress updates in the UI. Note the nice separation of concerns there, which tends to go out the window whenever people start using Dispatcher.

Both StartNew and Dispatcher are commonly seen in SO answers and blogs, but they're suboptimal solutions regardless.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810