編輯 我想強迫的正確方法是等待調用工人異步是一個Task.Run,像這樣:異步/等待與進度/取消長時間運行的API方法
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress)));
從http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx得到了一些光。
這應該很容易,但我是新來的異步/等待,所以忍受着我。我正在構建一個暴露API的類庫,其中包含一些長時間運行的操作。在過去,我用一個BackgroundWorker處理進度在這個簡化的代碼片段報告和取消,如:
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);
}
}
和客戶端代碼像:
BackgroundWorker worker = new BackgroundWorker
{ WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.DoWork += new DoWorkEventHandler(_myWorkerClass.DoSomething);
worker.ProgressChanged += WorkerProgressChanged;
worker.RunWorkerCompleted += WorkerCompleted;
worker.RunWorkerAsync(someparam);
現在,我想利用新的異步模式。所以,首先這裏是我如何在我的API中編寫一個簡單的長時間運行的方法;在這裏我只是逐行讀取文件中的行,只是爲了模擬真實世界的過程中,我將有一個轉換文件格式有一些處理:
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;
}
}
對於此示例的緣故,說這是DummyWorker類的一種方法。現在,這裏是我的客戶代碼(WPF測試應用程序):
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...
}
爲IProgress接口的實現來自http://blog.stephencleary.com/2010/06/reporting-progress-from-tasks.html,所以你可以參考該URL。無論如何,在這個使用測試中,UI被有效阻擋,我看不到任何進展。那麼參考消費代碼,對於這種情況,完整的畫面會是什麼?
是的,'Task.Run()'是做到這一點的方法。或者如果動作確實很長,可能會設置''Task.Factory.StartNew()'設置'LongRunning'選項。 – svick