Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Await on event handler

So here's deleagte and event

public delegate Task SomeEventHandler(SomeEventArgs e);

...


public event SomeEventHandler OnSomething;

Subscribers (multiple)

some.OnSomething += DoSomething;

...

public async Task DoSomething(SomeEventArgs e) {
    await SomethingElse();
    e.A = true;
}

Event call

if (this.OnSomething != null)
    await this.OnSomething(args);

// Here args.A is false
// It should be true

The problem is that last part continues even when DoSomething isn't finished. What would be the problem?

like image 814
Aleksandar Toplek Avatar asked Mar 20 '14 03:03

Aleksandar Toplek


People also ask

Can an event handler be async?

Instead, you have to cast event handlers as async void if you want to run async code inside of an event handler method and to comply with the classic . NET event delegate signature. However, the real problem is that the event delegate is not called from a Task based context.

Does await block the thread?

The await operator doesn't block the thread that evaluates the async method. When the await operator suspends the enclosing async method, the control returns to the caller of the method.

What is the use of await in C#?

For I/O-bound code, you await an operation that returns a Task or Task<T> inside of an async method. For CPU-bound code, you await an operation that is started on a background thread with the Task. Run method.

What are event handlers?

In programming, an event handler is a callback routine that operates asynchronously once an event takes place. It dictates the action that follows the event. The programmer writes a code for this action to take place. An event is an action that takes place when a user interacts with a program.

How to use awaitkeyword inside an event handler?

If one needs to use the awaitkeyword inside an event handler code, the method itself must be async void The following is an example of this: publicsealedpartialclassMainPage:Page publicMainPage() InitializeComponent(); Loaded +=MainPage_Loaded; privateasyncvoidMainPage_Loaded(objectsender,Windows. UI. Xaml. RoutedEventArgse)

Why can't I await a standard event handler?

If you need to await a standard .net event handler you can't do that, because it's void.

Why do async event handlers return void?

Event handlers naturally return void, so async methods return void so that you can have an asynchronous event handler. However, some semantics of an async void method are subtly different than the semantics of an async Task or async Task<T> method.

How do I subscribe to event handlers?

To subscribe an event handler, you'll use the familiar syntax (the same as in Simon_Weaver's answer): myViewModel.SearchRequest += async (s, e) => { await SearchOrders (); }; To invoke the event, use the same pattern we use for c# events (only with InvokeAsync):


1 Answers

The problem here is that multiple instances of SomeEventHandler are running hence there are multiple Task values being created. The await call is only running on one of them hence it's somewhat up to chance as to whether or not it's theDoSomething method that ends up being awaited.

To fix this you will need to await on every Task value that is created

if (this.OnSomething != null) {
  foreach (var d in this.OnSomething.GetInvocationList().Cast<SomeEventHandler>()) {
    await d(args);
  }
]
like image 185
JaredPar Avatar answered Sep 27 '22 23:09

JaredPar