简体   繁体   中英

AsyncEx DeferralManager for awaiting event handlers

I have a similar problem stated in this thread and according to Stephen Cleary's comment, WinRT's solution is to use deferrals. The solution indicated in the thread also works for me but I wanted to try out using deferrals since it might be or become the standard way of handling this kind of situation.

So I read his blog about it and tried to apply it to my code, but I can't seem to get it to work. What's happening is that event subscription is still not being awaited. I also couldn't find any full sample program that I can run and analyze. So I tried creating a sample console program to demonstrate the problem that I was seeing.

First I have the event handler delegate and event arguments definitions:

public delegate void CancelEventHandlerAsync(object sender, CancelEventArgsAsync e);

public class CancelEventArgsAsync : CancelEventArgs
{
    private readonly DeferralManager _deferrals = new DeferralManager();

    public IDisposable GetDeferral()
    {
        return this._deferrals.GetDeferral();
    }

    public Task WaitForDefferalsAsync()
    {
        return this._deferrals.SignalAndWaitAsync();
    }
}

Then the child module definition that is the event sender:

public class ChildModule1
{
    public event CancelEventHandlerAsync ChildModuleLaunching;

    public async Task Launch()
    {
         var cancelEventArgs = new CancelEventArgsAsync();
         this.ChildModuleLaunching(this, cancelEventArgs);
         cancelEventArgs.WaitForDefferalsAsync();
         if (cancelEventArgs.Cancel) 
         {
             return;
         }

         Console.WriteLine("Child module 1 launched."); // This should not be executed.
     }
}

Then the parent class that subscribes to the child module event:

public class Parent
{
    private ChildModule1 child1 = new ChildModule1();

    public Parent()
    {
        this.child1.ChildModuleLaunching += this.OnChildModule1Launching;
    }

    public async Task Process()
    {
        await this.child1.Launch();
    }

    private async void OnChildModule1Launching(object sender, CancelEventArgsAsync e)
    {
        var deferral = e.GetDeferral();

        await Task.Delay(2500); // Simulate processing of an awaitable task.
        e.Cancel = true;

        deferral.Dispose();
    }
}

Finally, the console app entry point:

static void Main(string[] args)
{
    var parent = new Parent();

    parent.Process().Wait();

    Console.ReadKey();
}

您需要await WaitForDefferalsAsync调用:

await cancelEventArgs.WaitForDefferalsAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM