2016-08-26 27 views
3

我一直使用BackgroundWorker的,我是新来的异步/等待关键字。现在,我想从BackgroundWorker的重构一些代码,以异步/等待(这是一个WPF MVVM应用程序)。重构BackgroundWorker的非同步的/等待

GenerateCommand = new DelegateCommand(GenerateHandler, CanGenerate); 

我见过有一个“AsyncCommand”在开发表达lib下,这可能会为我工作:

我在虚拟机,这是实例化这样得到的命令。

所有处理程序都会将事件处理程序注册到完成的事件并在服务上调用生成方法。

private void GenerateHandler() 
{ 
    generatorService.GenerationFinished += OnGenerationFinished; 
    generatorService.Generate(mDataFields, mGenerateFilesViewModel, mAmount);  
} 

然后,服务的生成方法启动一个BackgroundWorker:

public void Generate(IEnumerable<IDataField> dataFields, IGenerateFilesViewModel generateFilesViewModel, int amount) 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += worker_DoWork; 
    worker.RunWorkerAsync(); 
} 

的DoWork的方法不消耗我不确定我必须标记该方法中,时间任务

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    GenerateCommand generateCommand = null; 
    if (mUploadFiles) 
    { 
    generateCommand = new GenerateCommand(mDataFields, mOutputDirectory, mTemplateFileName, mAmount, mSelectedCollection, mSelectedAccountKey); 
    } 
    else 
    { 
    generateCommand = new GenerateCommand(mDataFields, mOutputDirectory, mTemplateFileName, mAmount); 
    } 

    try 
    { 
    generateCommand.Execute(); 
    } 
    catch (SEHException ex) 
    { 
    Console.WriteLine(String.Format("Generation of files threw an exception. {0}", ex.Message)); 
    } 
} 

与async关键字现在和我必须等待我的异步方法。我tryed以纪念worker_DoWork为异步和等待的生成方法的调用,但随后的生成方法,已被标记为异步太为了awaitable在VM的GenerateHandler?

很抱歉,如果我迷惑你,但是这一切都是升技混淆我...

感谢您的帮助

+0

您应该能够完全迁移到异步/通过改写DoWork的事件处理异步方法的await和在代码中的某处等待,然后完全删除BackgroundWorker。 –

+0

'GenerateHandler'和'GenerateMdfHandler'是一个错字还是他们是不同的方法? – Sam

+0

@Sam这是一个错字,很抱歉 – user3292642

回答

3

一个异步/ AWAIT语法糖好处就是方便编码的 - 你可以写真正的异步方法就像通常写同步方法一样。

在这里你有worker_DoWork重载荷和OnGenerationFinished最后的方法。所以,你的GenerateHandler可以是这样的:

private async void GenerateHandler() 
{ 
    await Task.Run(() => worker_DoWork()); 

    OnGenerationFinished(); 
} 

如果您OnGenerationFinished方法逻辑并不直接改变任何UI元素,你甚至可以更用ConfigureAwait卸载UI线程:

await Task.Run(() => worker_DoWork()).ConfigureAwait(false); 

在这里,我展示的想法,而不考虑你的特定的实现。你的最终实现可能不完全相同。

一些注意事项:

通常异步方法应该返回TaskTask<T>,但只要GenerateHandler实际上是命令的处理程序,它是在这种情况下,正常的有无效回报类型。

如何这个例子就可以了(在简单的话):

GenerateHandler在UI线程调用后,Task.Run将委托worker_DoWork处理来自线程池的线程,因此UI线程响应UI事件仍然是免费的。

什么等待关键字做:Task.Run在线程池创建任务后,它只是从GenerateHandler返回。但是它记得方法的其余部分(在这种情况下为OnGenerationFinished)和当前同步上下文(在这种情况下是UI线程),其中在worker_DoWork将完成该工作之后将处理该方法的其余部分。

但是,如果你不需要UI线程OnGenerationFinished处理,你可以告诉等待不使用当前同步上下文调用方法的其余部分,这是ConfigureAwait(false)的。在这种情况下,OnGenerationFinished将在线程池中的另一个线程中执行,从而使UI线程不会分散非UI作业。

0

我不认为这是一个很好的做法,但它工作得很好,对我来说:

void Something() 
    { 
    if (!mybworker.IsBusy()) 
    { 
     mybworker.RunWorkerAsync(); 
    } 
    while (mybworker.IsBusy()) 
    { 
    Application.DoEvents(); 
    } 
    }