Let's say I have a Form
that tries to deal with a multi-threaded environment; it therefore checks if it's running on the UI thread before any UI modification is done:
partial class SomeForm : Form
{
public void DoSomethingToUserInterface()
{
if (InvokeRequired)
{
BeginInvoke(delegate { DoSomethingToUserInterface() });
}
else
{
… // do the actual work (e.g. manipulate the form or its elements)
}
}
}
Now let's say I am performing some lengthy operation inside the …
part of that method; I'd therefore like to make it asynchronous using async/await
.
Given that I should change the method signature to return a Task
instead of void
(so that exceptions can be caught), how would I implement the part that performs the BeginInvoke
? What should it return?
public async Task DoSomethingToUserInterfaceAsync()
{
if (InvokeRequired)
{
// what do I put here?
}
{
… // like before (but can now use `await` expressions)
}
}
When using
async-await
with a customawaiter
such as the commonTaskAwaiter
, theSynchronizationContext
is being implicitly captured for you. Later, when the asynchronous method completes, the continuation (any code after theawait
) is being marshaled back to that same sync context usingSynchronizationContext.Post
.This altogether eliminates the need to use
InvokeRequired
and other techniques used to mainpulate work on the UI thread. In order to do that, you'll have to trace your method calls all the way to the top level ones and refactor them to useasync-await
probably.But, to address the specific problem as is, what you can do is capture the
WinFormSynchronizationContext
when yourForm
initializes:And later use it when you want to
await
: