Windows 8 - 等待 Task<Bool> - 需要对已完成的侦听器进行异步回调

Posted

技术标签:

【中文标题】Windows 8 - 等待 Task<Bool> - 需要对已完成的侦听器进行异步回调【英文标题】:Windows 8 - await Task<Bool> - async call back on completed listener required 【发布时间】:2012-08-03 01:13:54 【问题描述】:

我有一个函数,它从存储中打开一个文件并返回一个布尔值,指定文件打开得很好。

private async Task<bool> SaveImage()

    try
    
        await filesave.openAsync(FileAccessMode.ReadWrite)
    
    catch()
    
        return false;
    

    return true;

我想调用 await SaveImage() 函数,但不知何故想要一个侦听器/事件处理程序,它告诉我何时完成。完成后我想用新数据更新我的布局。使用适用于 Windows 8 的新 WINRT 异步/等待异步方法如何实现这一点?是否有解决方法/替代方法。

如何设置事件处理程序类型方案? (完成)

【问题讨论】:

【参考方案1】:

这需要更多的代码,但它是处理异步操作、进度、取消和完成状态的一种非常酷且有用的方法。这是在 VS2012 Winrt Store 应用程序中编译的,我通过单击按钮运行它,如您在此处看到的。

    private void Save_File_Click(object sender, RoutedEventArgs e)
    
        // create your op, bool = return type, string = progress report
        IAsyncOperationWithProgress<bool, string> op;

        // Call our async operation with progress sending the file name
        op = OpenFileWithProgress("test.txt");

        //  not implemented here
        //op.Cancel(); 

        // when we get a progress update...
        op.Progress = (info, progress) =>
        
            // I'm just giving text feed back to user here
            Debug.WriteLine(progress);
        ;
        op.Completed = (info, status) =>
        
            // check status for completion or cancellation...
            switch (status)
            
                case AsyncStatus.Completed:
                    //  Do your completed work here
                    Debug.WriteLine("Completed");
                    break;
                case AsyncStatus.Canceled:
                    // Operation canceled - not implemented...
                    Debug.WriteLine("Canceled");
                    break;
                default:
                    // default stuff here
                    break;
            
        ;
    

    public IAsyncOperationWithProgress<bool, string> OpenFileWithProgress(string fileName)
    
        return System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run<bool, string>((token, progress) =>
            Task.Run<bool>(async () =>
            
                progress.Report("Starting");
                try
                
                    StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName);
                
                catch (Exception ex)
                
                    return false;
                

                progress.Report("Finished");

                return true;

            , token));
    

【讨论】:

【参考方案2】:

Joe 的回答看起来很棒,但如果您坚持使用事件 - 例如,如果您的 SaveImage() 调用位于与更新布局无关的各个代码区域 - 您可以在操作完成时引发事件。您可以使用普通的旧 CLR 事件或使用 pub-sub pattern 实现,例如 Prism 的 EventAggregator 或 MVVM Light 的 Messenger。 POCE 版本可能是这样的

public event EventHandler<Tuple<StorageFile,bool>> SaveImageCompleted;

private async Task<bool> SaveImage(StorageFile file)

    try
    
        await file.OpenAsync(FileAccessMode.ReadWrite);
    
    catch
    
        if (SaveImageCompleted != null)
            SaveImageCompleted(this, new Tuple<StorageFile, bool>(file, false));

        return false;
    

    if (SaveImageCompleted != null)
        SaveImageCompleted(this, new Tuple<StorageFile, bool>(file, true));

    return true;

【讨论】:

【参考方案3】:

您只需await 调用您的方法,然后在其后面加上完成后应该运行的代码。您无需手动注册事件处理程序。

var succeeded = await SaveImage();
// Because of the "await" keyword in the above line, the current method
// will not continue until "SaveImage" has completed its async work and
// signaled its Task
if (succeeded)  ... 

当然,由于上面的代码使用了await 关键字,因此需要将它放在一个也标记为async 的方法中。如果该方法需要向 its 调用者发出完成信号,那么它还应该返回一个TaskTask&lt;T&gt;;例如:

private async Task<string> MyHelperMethod() 
    var succeeded = await SaveImage();
    if (succeeded)
        return "Success";
    else
        return "Failure";

// then, in some other method:
    var message = await MyHelperMethod();

或者,如果调用SaveImage 的方法是行尾——假设它是ButtonClick 事件的处理程序——那么它可以是async void

private async void ButtonClick(object sender, EventArgs args) 
    var succeeded = await SaveImage();
    if (succeeded)  ... 

【讨论】:

注意:尽管方法中的其余行等待等待的方法完成,但调用该方法的方法将获得控制流执行。见msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

以上是关于Windows 8 - 等待 Task<Bool> - 需要对已完成的侦听器进行异步回调的主要内容,如果未能解决你的问题,请参考以下文章

在 WCF 中返回或等待 Task<T>

等待 Task.CompletedTask 是为了啥?

多线程等待返回

合并 Observable 列表并等待所有完成

Java线程池ThreadPoolExecuter:execute()原理

等待 Task.Delay() 与 Task.Delay().Wait()