bearbeiten Ich nehme an, die richtige Art und Weise erwarten zwingt die Arbeiter asynchron mit einem Task.Run, wie dies aufzurufen:Async/erwartet für lang laufende API-Methoden mit progress/Abbruch
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress)));
Habe etwas Licht von http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx bekommen.
dies sollte einfach sein, aber ich bin neu zu async/erwarten so mit mir zu tragen. Ich baue eine Klassenbibliothek auf, die eine API mit einigen lang andauernden Operationen ausstellt. In der Vergangenheit habe ich eine Background mit Fortschrittsberichte und Abbruch zu tun, wie in diesem vereinfachten Codefragment:
public void DoSomething(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = (BackgroundWorker)sender;
// e.Argument is any object as passed by consumer via RunWorkerAsync...
do
{
// ... do something ...
// abort if requested
if (bw.CancellationPending)
{
e.Cancel = true;
break;
} //eif
// notify progress
bw.ReportProgress(nPercent);
}
}
und der Client-Code war wie:
BackgroundWorker worker = new BackgroundWorker
{ WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.DoWork += new DoWorkEventHandler(_myWorkerClass.DoSomething);
worker.ProgressChanged += WorkerProgressChanged;
worker.RunWorkerCompleted += WorkerCompleted;
worker.RunWorkerAsync(someparam);
Nun möchte Ich mag an Nutzen Sie das neue asynchrone Muster. Also, zuerst einmal hier ist, wie ich eine einfache lang laufende Methode in meiner API schreiben würde; hier bin ich nur eine Datei Zeile für Zeile zu lesen, nur einen realen Prozess zu emulieren, wo ich ein Dateiformat mit einiger Verarbeitung konvertieren müssen:
public async Task DoSomething(string sInputFileName, CancellationToken? cancel, IProgress progress)
{
using (StreamReader reader = new StreamReader(sInputFileName))
{
int nLine = 0;
int nTotalLines = CountLines(sInputFileName);
while ((sLine = reader.ReadLine()) != null)
{
nLine++;
// do something here...
if ((cancel.HasValue) && (cancel.Value.IsCancellationRequested)) break;
if (progress != null) progress.Report(nLine * 100/nTotalLines);
}
return nLine;
}
}
Aus Gründen des dieses Beispiels sagen, das ist eine Methode einer DummyWorker-Klasse. Nun, hier ist mein Client-Code (ein WPF-Test app):
private void ReportProgress(int n)
{
Dispatcher.BeginInvoke((Action)(() => { _progress.Value = n; }));
}
private async void OnDoSomethingClick(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog { Filter = "Text Files (*.txt)|*.txt" };
if (dlg.ShowDialog() == false) return;
// show the job progress UI...
CancellationTokenSource cts = new CancellationTokenSource();
DummyWorker worker = new DummyWorker();
await builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress));
// hide the progress UI...
}
Die Implementierung für die IProgress Schnittstelle kommt von http://blog.stephencleary.com/2010/06/reporting-progress-from-tasks.html, so dass Sie auf diese URL verweisen. Wie auch immer, in diesem Benutzertest wird die Benutzeroberfläche effektiv blockiert und ich sehe keinen Fortschritt. Was wäre das ganze Bild für ein solches Szenario, mit Bezug auf den konsumierenden Code?
Ja, 'Task.Run()' ist der Weg, dies zu tun. Oder möglicherweise 'Task.Factory.StartNew()' mit der Option 'LongRunning', wenn die Aktion wirklich lang ist. – svick