2016-05-31 8 views
-4

Ich habe eine Windows-Formular-Anwendung mit einem Knopf, der die folgenden Aktion auslöst:C# Task-Steuerablauflogik nicht richtig funktioniert

private async void timeStampDocuments_Click(object sender, System.EventArgs e) 
{ 
    await PerformTask(TimeStampPdfs()); 
} 

Die PerformTask Methode ist wie folgt:

private async System.Threading.Tasks.Task PerformTask(System.Threading.Tasks.Task task) 
{ 
    if(documentsView.CheckedItems.Count > 0) 
    { 
     Enabled = false; 
     try 
     { 
      await task; 
     } 
     catch(System.Exception e) 
     { 
      System.Windows.Forms.MessageBox.Show("Exception: " + e.Message); 
     } 
     progressBar.Value = 0; 
     progressBar.Text = string.Empty; 
     Enabled = true; 
    } 
    else 
    { 
     System.Windows.Forms.MessageBox.Show("Please select at least one document."); 
    } 
} 

Das Problem ist, Selbst wenn die Bedingung falsch ist (documentsView.CheckedItemsCount ist gleich 0), wird die Task weiterhin ausgeführt. Sobald die Aufgabe jedoch beendet ist, wird eine MessageBox mit der Meldung "Bitte wählen Sie mindestens ein Dokument aus" angezeigt.

Wenn es hilft, die TimeStampPdfs Methode ist:

private System.Threading.Tasks.Task TimeStampPdfs() => System.Threading.Tasks.Task.Run(() => 
    { 
     for (int i = 0; i < documentsView.CheckedItems.Count; i++) 
     { 
      var currentDocument = documentsView.CheckedItems[i].ToString(); 
      if (!string.Equals(
       System.IO.Path.GetExtension(currentDocument), ".pdf", System.StringComparison.InvariantCultureIgnoreCase)) 
      { 
       currentDocument = ConvertToPdf(currentDocument); 
      } 
      TimeStampPdf(currentDocument); 
      Report(new ProgressReport 
      { 
       Total = documentsView.CheckedItems.Count, 
       CurrentCount = i + 1 
      }); 
     } 
    }).ContinueWith(t => 
    { 
     System.Windows.Forms.MessageBox.Show("Files saved with time-stamp on print script in " + OutputRootPath); 
    }, 
     System.Threading.CancellationToken.None, 
     System.Threading.Tasks.TaskContinuationOptions.OnlyOnRanToCompletion, 
     System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext() 
    ); 

Ich weiß, dass es läuft, weil die „Dateien mit Zeitstempel auf dem Druck Skript gespeichert in ...“ Meldungsfeld angezeigt wird.

+2

ich sehe nicht, wie das kompiliert auch, weil 'TimeStampPdf' als void-Methode definiert ist, und doch sind Sie seinen * Rückgabewert mit (?) *' PerformTask' zu nennen ?? – sstan

+0

Sie übergeben auch keine 'Zeichenfolge' an' TimeStampPdf', wenn Sie sie aufrufen. – juharr

+0

@sstan Sorry, die falsche Methode gepostet. Ich habe zwei, die ähnliche Namen haben und in Eile einen sorglosen Fehler gemacht haben. Die richtige Methode ist jetzt in Frage. –

Antwort

1

Das Problem ist, dass die Aufgabe auch dann ausgeführt wird, wenn die Bedingung falsch ist (documentsView.CheckedItemsCount ist gleich 0).

Das ist, weil Ihr Code die TimeStampPdfs Aufgabe hier beginnt, vor Aufruf PerformTask:

await PerformTask(TimeStampPdfs()); 

Mit anderen Worten, await hat nicht die Aufgabe starten; Stattdessen startet TimeStampPdfs die Aufgabe und gibt eine Aufgabe zurück, die bereits ausgeführt wird. await dann (asynchron) wartet auf die Aufgabe abgeschlossen. Sie können meine async intro hilfreich finden.

Wenn ich Ihren Code richtig verstehe, wollen Sie wahrscheinlich einen Delegierten zu übergeben, die eine Aufgabe zurückgibt, wie folgt aus:

private async Task PerformTask(Func<Task> func) 
{ 
    if(documentsView.CheckedItems.Count > 0) 
    { 
    Enabled = false; 
    try 
    { 
     await func(); 
    } 
    ... 
} 


await PerformTask(() => TimeStampPdfs()); 

Auf einer Seite zur Kenntnis, empfehle ich mit await statt ContinueWith für TimeStampPdfs:

private async Task TimeStampPdfs() 
{ 
    await Task.Run(() => 
    { 
    ... 
    }); 
    MessageBox.Show("Files saved with time-stamp on print script in " + OutputRootPath); 
} 
+0

Danke, das hat es behoben. –