Question

I've written these extension methods which I'd like to condense into one, since they effectively do the exact same thing. The problem I've run into is that I cannot pass in an HtmlElementEventHandler as an EventHandler parameter.

    public static async Task WaitUntilAsync
        (this Action action, Action<EventHandler> addHandler,
        Action<EventHandler> removeHandler, Predicate<string> pred)
    {
        var t = new TaskCompletionSource<bool>();

        System.EventHandler handler = new System.EventHandler((s, e) => 
            {
                if (pred((s as MyAsyncWebBrowser).DocumentTitle))
                    t.SetResult(true);
            });

        addHandler(handler);

        action();
        await t.Task;

        removeHandler(handler);
    }

    public static async Task WaitUntilAsync
(this Action action, Action<System.Windows.Forms.HtmlElementEventHandler> addHandler,
Action<System.Windows.Forms.HtmlElementEventHandler> removeHandler, Predicate<string> = h => true)
    {
        var t = new TaskCompletionSource<bool>();

        System.Windows.Forms.HtmlElementEventHandler handler = new System.Windows.Forms.HtmlElementEventHandler((s, e) =>
        {
            if (pred)
                t.TrySetResult(true);
        });

        addHandler(handler);

        action();
        await t.Task;

        removeHandler(handler);
    }

Any ideas?

Previous Attempt

    public static async Task WaitUntilAsync<TDelegate>
        (this Action action, Action<TDelegate> addHandler,
        Action<TDelegate> removeHandler, Predicate<string> pred)
    {
        var t = new TaskCompletionSource<bool>();

        TDelegate handler = (s, e) =>
        {
            if (pred((s as MyAsyncWebBrowser).DocumentTitle))
                t.SetResult(true);
        };

        addHandler(handler);

        action();
        await t.Task;

        removeHandler(handler);
    }

Which gives me "Cannot Convert Lambda expression to Type Delegate because it is not a delegate type." at the very beginning.

Was it helpful?

Solution

Try this as your definition. Gotta love generics!

public static async Task WaitUntilAsync<T>(this Action action, Action<T> addHandler, Action<T> removeHandler, Predicate<string> pred) where T : class

Unfortunately, you cannot use delegates as generic constraints like so:

public static async Task WaitUntilAsync<T>(this Action action, Action<T> addHandler, Action<T> removeHandler, Predicate<string> pred) where T : EventHandler

...so you'll have to use reflection to confirm your type and then cast it manually.

Here is a complete example:

  public static async Task WaitUntilAsync<TDelegate>(this Action action, Action<TDelegate> addHandler, Action<TDelegate> removeHandler, Predicate<string> pred) where TDelegate : class
    {
        var delegateType = typeof(TDelegate);

        if (delegateType != typeof(EventHandler) && !delegateType.IsSubclassOf(typeof(EventHandler))) throw new Exception("TDelegate must be EventHandler or a subclass.");

        var t = new TaskCompletionSource<bool>();

        EventHandler realHandler = (sender, args) =>
        {
            //do real event work here
        };

        var handler = Delegate.CreateDelegate(delegateType, realHandler.Method) as TDelegate;

        addHandler(handler);

        action();
        await t.Task;

        removeHandler(handler);
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top