Je dois déclencher un rappel lorsque la boucle foreach
a fini de parcourir chaque élément du 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());
}
}
}
}
}
Est-ce possible et si oui comment cela peut-il être fait?
C'est très simple, il suffit de passer une méthode en tant que délégué en paramètre. invoquez-le ensuite où vous le souhaitez.
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.
}
Je coderais comme ci-dessous. De cette façon, vous gardez toujours une trace de la tâche en attente (_pendingSearch
), alors que startSearchBtn_Click
reste synchrone.
Vous devriez garder une trace des tâches en attente (et pouvoir les annuler). Sinon, l'utilisateur peut cliquer sur startSearchBtn
deux fois de suite et créer deux tâches de recherche. Cela peut toujours être un scénario valable dans votre cas, mais ce n’est généralement pas le cas.
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] Utilisation de 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
}
Puisque vous utilisez await
, votre code dans startSearchBtn_Click
ne continuera pas tant que Search
n'est pas terminé.
Tout ce dont vous avez besoin est quelque chose comme ceci:
private async void startSearchBtn_Click(object sender, EventArgs e)
{
await Search(files, selectTxcDirectory.SelectedPath, status);
// run your callback here
}