2016-08-26 3 views
3

저는 Backgroundworker를 항상 사용했으며 비동기/대기 키워드를 처음 사용했습니다. 지금은 Backgroundworker에서 async/await (WPF MVVM 앱)의 코드를 리팩터링하려고합니다.리팩토링 배경 작업자를 async/await으로 변경

GenerateCommand = new DelegateCommand(GenerateHandler, CanGenerate); 

아마 나를 위해 작동 dev에있는 'AsyncCommand'LIB 표현이가 본 적이 :

나는 다음과 같이 인스턴스화 내 VM에서 명령을 받았습니다.

모든 처리기는 완료 이벤트에 이벤트 핸들러를 등록하고 서비스에서 Generate 메소드를 호출합니다.

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 키워드를 사용하여 현재 비동기 메소드를 기다리고 있어야합니다. worker_DoWork를 async로 표시하고 Generate 메서드에서 호출을 기다리고 있지만 Generate 메서드는 VM의 GenerateHandler에서 기다릴 수 있도록 비동기로 표시되어야합니까? 죄송합니다

내가 당신을 혼란 합니다만,이 모든 ABIT 저를 혼동하는 경우 ... 도움 비동기/await를 구문 설탕 혜택 코딩되어 편리

+0

것은 당신은 완전히 마이그레이션 할 수 있어야에 비동기/await를 비동기 방식으로 DoWork 이벤트 핸들러를 다시 작성하여 및 코드 어딘가에 그것을 기다리고 BackgroundWorker를 완전히 제거하십시오. –

+0

'GenerateHandler'와'GenerateMdfHandler'는 오타입니다, 아니면 다른 방법입니까? – Sam

+0

@Sam 그것은 오타되었습니다, 미안 해요. – user3292642

답변

3

하나에 대한

감사 - 당신은 쓸 수 있습니다 진정으로 비동기 메서드는 동기식 메서드를 쓰는 것과 마찬가지입니다.

여기에는 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); 

내가 보여 아이디어, 귀하의 특정을 고려하지 않고 generatorService 실현. 아마 당신의 최종 실현은 정확히 같지 않을 것입니다.

일부 노트 :

보통 비동기 방법은 Task 또는 Task<T>를 반환해야하지만, 곧 GenerateHandler로 실제로 명령의 핸들러, 무효 수익을 가질 경우에 정상 유형.

UI 스레드에서 호출 GenerateHandler 후, Task.Run이 스레드에서 스레드에 worker_DoWork 처리를 위임되므로 UI ​​스레드는 UI의 이벤트에 응답 무료로 남아 :

이 예 (간단한 단어에) 작동 방법. 키워드를 기다리고 무엇

는 수행 Task.Run이 스레드에서 작업을 생성 한 후, 그냥 GenerateHandler에서 반환합니다. 그러나 나머지 메서드 (이 경우 OnGenerationFinished)와 현재 동기화 컨텍스트 (이 경우 UI 스레드)를 기억하며 worker_DoWork이 작업을 완료 한 후에 나머지 메서드가 처리됩니다.

는하지만 OnGenerationFinished 처리를 위해 UI 스레드를 필요로하지 않는 경우에, 당신은 이 방법의 나머지 부분을 호출하는 현재 동기화 컨텍스트를 사용하지을 기다리고 알 수 있습니다, 이것은 무엇 ConfigureAwait(false)입니다. 이 경우 OnGenerationFinished은 threadpool의 다른 스레드에서 실행되어 UI 스레드가 비 UI 작업을 방해하지 않도록합니다.

0

나는 이것이 좋은 방법이지만 나를 위해 잘 작동합니다 생각하지 않습니다

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