I want to await
a button.click()
event. For that created an extension GetAwaiter()
method:
public static class ButtonAwaiterExtensions
{
public static ButtonAwaiter GetAwaiter(this Button button)
{
return new ButtonAwaiter()
{
Button = button
};
}
public class ButtonAwaiter : INotifyCompletion
{
public bool IsCompleted
{
get { return false; }
}
public void GetResult()
{
}
public Button? Button { get; set; }
public void OnCompleted(Action continuation)
{
RoutedEventHandler? h = null;
h = (o, e) =>
{
Button!.Click -= h;
continuation();
};
Button!.Click += h;
}
}
}
(I found it here: http://blog.roboblob.com/2014/10/23/awaiting-for-that-button-click/)
With that I can await the Button1.Click()
event directly with await Button1;
which is great.
BUT I couldn't figure out how to combine this awaitable with someting like await Task.WhenAny()
I tried
await Task.WhenAny(Button1, Button2);
It will tell me that it "cannot convert from Button to Task".
I thougt I found the solution here: Using `Task.WhenAll` with `INotifyCompletion` by just adding a method
public static async Task GetTask()
{
await this;
}
to my ButtonAwaiterExtensions class, but the keyword this
cannot be used in my static class.
I cannot figure out what to return in the method or generally how to await
any Button.Click()
. Any ideas?
Thanks to Sebastian Schumann comment (how can I combine await.WhenAny() with GetAwaiter extension method) I solved my problem by adding another extension method directly to my ButtonAwaiterExtensions class:
public async static Task AsTask(this Button self) => await self;
Complete solution:
public static class ButtonAwaiterExtensions
{
public static ButtonAwaiter GetAwaiter(this Button button)
{
return new ButtonAwaiter()
{
Button = button
};
}
public class ButtonAwaiter : INotifyCompletion
{
public bool IsCompleted
{
get { return false; }
}
public void GetResult()
{
}
public Button? Button { get; set; }
public void OnCompleted(Action continuation)
{
RoutedEventHandler? h = null;
h = (o, e) =>
{
Button!.Click -= h;
continuation();
};
Button!.Click += h;
}
}
public async static Task AsTask(this Button self) => await self;
}
An alternative (little shorter) Implementation for GetAwaiter
might be:
public static TaskAwaiter GetAwaiter(this Button self)
{
ArgumentNullException.ThrowIfNull(self);
TaskCompletionSource tcs = new();
self.Click += OnClick;
return tcs.Task.GetAwaiter();
void OnClick(object sender, EventArgs args)
{
self.Click -= OnClick;
tcs.SetResult();
}
}