I\'d like to have a generic reusable piece of code for wrapping EAP pattern as task, something similar to what Task.Factory.FromAsync does for BeginXXX/EndXXX APM pattern.>
I have a (usage wise) much shorter Solution. I will show you the usage first and then give you the code that makes this happen (use it freely).
usage eg:
await button.EventAsync(nameof(button.Click));
or:
var specialEventArgs = await busniessObject.EventAsync(nameof(busniessObject.CustomerCreated));
or for Events that need to be triggered in some way:
var serviceResult = await service.EventAsync(()=> service.Start, nameof(service.Completed));
the magic that makes this happen (beware it's C# 7.1 syntax but can easily be converted back to lower language versions by adding a few lines):
using System;
using System.Threading;
using System.Threading.Tasks;
namespace SpacemonsterIndustries.Core
{
    public static class EventExtensions
    {
        /// 
        /// Extension Method that converts a typical EventArgs Event into an awaitable Task 
        ///  
        /// The type of the EventArgs (must inherit from EventArgs) 
        /// the object that has the event
        /// optional Function that triggers the event
        /// the name of the event -> use nameof to be safe, e.g. nameof(button.Click) 
        /// an optional Cancellation Token
        ///  
        public static async Task EventAsync(this object objectWithEvent, Action trigger, string eventName, CancellationToken ct = default)
            where TEventArgs : EventArgs
        {
            var completionSource = new TaskCompletionSource(ct);
            var eventInfo = objectWithEvent.GetType().GetEvent(eventName);
            var delegateDef = new UniversalEventDelegate(Handler);
            var handlerAsDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, delegateDef.Target, delegateDef.Method);
            eventInfo.AddEventHandler(objectWithEvent, handlerAsDelegate);
            trigger?.Invoke();
            var result = await completionSource.Task;
            eventInfo.RemoveEventHandler(objectWithEvent, handlerAsDelegate); 
            return result;
            void Handler(object sender, TEventArgs e) => completionSource.SetResult(e);
        }
        public static Task EventAsync(this object objectWithEvent, string eventName, CancellationToken ct = default) where TEventArgs : EventArgs
            => EventAsync(objectWithEvent, null, eventName, ct);
        private delegate void UniversalEventDelegate(object sender, TEventArgs e) where TEventArgs : EventArgs;
    }
}