如何等待事件点击

问题描述 投票:0回答:2

我正在尝试等待按下按钮时触发的回调。重要的一点是,我要等待简单的await中的回调,而无需重新设计代码。换句话说,我要实现以下目标:

internal async Task BatchLogic()
{
    ProgressMessage = "Batch Logic Starts";
    await OnCallbackFired();
    ProgressMessage = "Batch Logic Ends";
}

我的尝试是

internal async Task BatchLogic()
{
    ProgressMessage = "Batch Logic Starts";
    await Task.Factory.FromAsync(beginMethod, endMethod, state);
    ProgressMessage = "Batch Logic Ends";
}

具有以下定义

 private object state = null;
 private void endMethod(IAsyncResult obj)
 {
     IsBusy = false; 
 }
 private AsyncCallback callback;
 private IAsyncResult beginMethod(AsyncCallback callback, object state)
 {
     return Task.FromResult(true);
 }

当按下按钮时,将执行以下代码:

private async void RunNext()
{
    isBusy = true;
    await workToDo();
    isBusy = false; // the first 3 lines are not relevant
    callback = new AsyncCallback(endMethod);
    callback.Invoke(Task.FromResult(true));
}

问题是endMethod是从callback.Invoke调用的,但是Factory.FromAsync从未返回,这很可能是因为我不了解如何使用它,也没有找到与我所用的示例相对应的示例我试图实现。

c# async-await asynccallback
2个回答
1
投票

await,它必须是Task(这是一个过分的简化,但这是重要的部分)((C#可以await任何公开了TaskAwaiter GetAwaiter()方法的对象,但95%的C#开发人员将消耗Task / Task<T>对象的时间)。

要创建Task,请使用TaskCompletionSource。这样就可以围绕其他概念性“任务”创建Task表示形式,例如IAsyncResult样式的API,线程,重叠的IO等。

假设这是WinForms,然后执行此操作:

class MyForm : Form
{
    // Note that `TaskCompletionSource` must have a generic-type argument.
    // If you don't care about the result then use a dummy null `Object` or 1-byte `Boolean` value.
    private TaskCompletionSource<Button> tcs;

    private readonly Button button;

    public MyForm()
    {
        this.button = new Button() { Text = "Click me" };
        this.Controls.Add( this.button );
        this.button.Click += this.OnButtonClicked;
    }

    private void OnButtonClicked( Object sender, EventArgs e )
    {
        if( this.tcs == null ) return;

        this.tcs.SetResult( (Button)sender );
    }

    internal async Task BatchLogicAsync()
    {
        this.tcs = new TaskCompletionSource<Button>();

        ProgressMessage = "Batch Logic Starts";

        Button clickedButton = await this.tcs.Task;

        ProgressMessage = "Batch Logic Ends";
    }
}

0
投票

可接受的答案要简单得多,但是,出于此原因,这是我的初始代码的解决方案,它可以按预期运行。我必须为回调定义一个闭包

AsyncCallback callback;

然后我不得不将callbackbeginMethod传递给闭包:

private IAsyncResult beginMethod(AsyncCallback callback, object state)
{
    this.callback = callback;
    return Task.FromResult(true);
}

最后从事件中调用它(即,用于WPF的MVVM中的Command方法)

private async void RunNext()
{
    IsBusy = true;
    ProgressMessage = "Wait 10 seconds...";
    await workToDo();
    ProgressMessage = "Work done!";
    IsBusy = false;
    if (callback != null)
    {
        callback.Invoke(Task.FromResult(true));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.