C# 异步任务方法后触发回调

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19003594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:52:30  来源:igfitidea点击:

Fire callback after async Task method

c#async-await

提问by jskidd3

I need to fire a callback when the foreachloop has finished searching through each item int the List<>.

我需要在foreach循环完成搜索每个项目时触发回调List<>

private async void startSearchBtn_Click(object sender, EventArgs e)
{
    await Search(files, selectTxcDirectory.SelectedPath, status);
}

private static async Task Search(List<string> files, string path, Label statusText)
{
    foreach (string file in files)
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(file);

        statusText.Text = "Started scanning...";
        using (XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.InnerXml), new XmlReaderSettings() { Async = true }))
        {
            while (await reader.ReadAsync())
            {
                if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "LineName"))
                {
                    Console.WriteLine(reader.ReadInnerXml());
                }
            }
        }
    }
}

Is this possible and if so how can it be done?

这是可能的,如果可以,怎么做?

采纳答案by Sriram Sakthivel

It is very simple, just pass a method as a delegate in parameter. then invoke it wherever you need.

很简单,只需在参数中传递一个方法作为委托即可。然后在任何需要的地方调用它。

private async void startSearchBtn_Click(object sender, EventArgs e)
{
    await Search(files, selectTxcDirectory.SelectedPath, status, SearchCompleted); // <-- pass the callback method here
}

private static async Task Search(List<string> files, string path, Label statusText, Action<string> callback)
{
    foreach (string file in files)
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(file);

        statusText.Text = "Started scanning...";
        using (XmlReader reader = XmlReader.Create(new StringReader(xmlDoc.InnerXml), new XmlReaderSettings() { Async = true }))
        {
            while (await reader.ReadAsync())
            {
                if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "LineName"))
                {
                    Console.WriteLine(reader.ReadInnerXml());
                }
            }
        }

        // Here you're done with the file so invoke the callback that's it.
        callback(file); // pass which file is finished
    }
}

private static void SearchCompleted(string file)
{
    // This method will be called whenever a file is processed.
}

回答by Kendall Frey

Since you're using await, your code in startSearchBtn_Clickwon't continue until Searchis finished.

由于您正在使用await,您的代码在完成startSearchBtn_Click之前不会继续Search

All you need is something like this:

你所需要的只是这样的:

private async void startSearchBtn_Click(object sender, EventArgs e)
{
    await Search(files, selectTxcDirectory.SelectedPath, status);
    // run your callback here
}

回答by noseratio

I'd code it like below. This way, you still keep track of the pending task (_pendingSearch), while startSearchBtn_Clickremains synchronous.

我会像下面这样编码。这样,您仍然可以跟踪挂起的任务 ( _pendingSearch),同时startSearchBtn_Click保持同步。

You should be keeping track of pending tasks (and be able to cancel them). Otherwise, user may click startSearchBtntwice in a row and spawn two search tasks. This still may be a valid scenario in your case, but usually it is not.

您应该跟踪挂起的任务(并能够取消它们)。否则,用户可能会startSearchBtn连续单击两次并生成两个搜索任务。在您的情况下,这仍然可能是一个有效的场景,但通常不是。

Task _pendingSearch = null;
private void startSearchBtn_Click(object sender, EventArgs e)
{
    // check if is _pendingSearch != null and still pending here

    _pendingSearch = Search(files, 
        selectTxcDirectory.SelectedPath, status).ContinueWith((finishedTask) => 
    {
        // Place your completion callback code here
    }, TaskScheduler.FromCurrentSynchronizationContext);
}

private static async Task Search(List<string> files, string path, Label statusText)
{
    // ...
}

[EDITED]Using await:

[编辑]使用await

Task _pendingSearch = null;
private async void startSearchBtn_Click(object sender, EventArgs e)
{
    // check if is _pendingSearch != null and still pending here

    _pendingSearch = Search(files, selectTxcDirectory.SelectedPath, status);
    await _pendingSearch;
    // Place your completion callback code here
}