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?
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.
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.
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.
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.
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)
If you need to await a standard .net event handler you can't do that, because it's 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.
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):
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);
}
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With