异步任务方法后的回调

时间:2013-09-25 11:24:34

标签: c# async-await

我需要在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());
                }
            }
        }
    }
}

这可能吗?如果可以的话怎么办呢?

3 个答案:

答案 0 :(得分:18)

这很简单,只需将方法作为参数传递给参数。然后在任何需要的地方调用它。

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.
}

答案 1 :(得分:3)

我会在下面编写代码。这样,您仍然可以跟踪待处理任务(_pendingSearch),同时startSearchBtn_Click保持同步。

您应该跟踪待处理的任务(并且能够取消它们)。否则,用户可以连续两次单击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)
{
    // ...
}

[已编辑] 使用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
}

答案 2 :(得分:1)

由于您使用的是await,因此startSearchBtn_Click中的代码在Search完成之前不会继续。

你需要的就是这样:

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