Изменить Я полагаю, что правильный способ заставить await вызывать воркер асинхронно — это Task.Run, например:
await Task.Run(() => builder.Build(dlg.FileName, cts.Token, new Progress(ReportProgress)));
Немного информации с сайта http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/10293335.aspx.
это должно быть легко, но я новичок в async/await, так что терпите меня. Я создаю библиотеку классов, предоставляющую 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. Во всяком случае, в этом тесте использования пользовательский интерфейс эффективно заблокирован, и я не вижу никакого прогресса. Итак, какова будет полная картина для такого сценария со ссылкой на потребляющий код?
Task.Run()это способ сделать это. Или, возможно,Task.Factory.StartNew()с установленной опциейLongRunning, если действие действительно долгое. - person svick   schedule 23.10.2012