2014-06-18 1 views
0

비동기 메서드를 사용하여 UI를 작동시키는 데 문제가 있습니다. 여기 내 코드의 일부이다async를 사용할 때 UI가 정지 함

private async void btnDoOutput_Click(object sender, RoutedEventArgs e) 
{ 
    /* Initiliaze */ 
    groupBoxConfiguration.IsEnabled = false; 

    var progressIndicator = new Progress<int>(); 
    progressIndicator.ProgressChanged += (s,value) => 
    { 
     progressExport.Value = (double)value; 
     labelPercentage.Content = "Export in progress : " + value + " %"; 
    }; 
    /* do Work */ 

    switch (something) 
    { 
     case 1: 
      await method(input, output, options, progressIndicator); 
      break; 
     default: break; 
    } 

    /* Finalization */ 
    groupBoxConfiguration.IsEnabled = true; 
} 

방법은 진행이 끝날 때까지 표시되지 않습니다,

public async static Task<string> method(string input, string output, string options, IProgress<int> progress) 
{ 
    while(something) 
    { 
     //operations on input and output 

     if (progress != null) 
     { 
      progress.Report(percentage); 
     } 
    } 
} 

내 버튼의 UI 동결을 클릭

가의 그룹 상자는 여전히 사용할 수 있습니다.

+10

을 반환합니다. 'method'는 아무 것도 반환하지 않지만'Task '입니다. Async/await는 "마술처럼 내 코드 비동기"가 아닙니다. "이 코드는 이미 비동기이며 작업하기 쉽습니다." 실제로 비동기식 코드에서 아무 것도 보이지 않습니다. – cadrell0

+1

비동기 방식의 진행보고 및 취소 기능을 사용하려면 다음 MSDN 링크를 사용해야합니다. http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4 -5-enabling-progress-cancellation-in-async-apis.aspx –

+0

'return Task.Factory.StartNew (() => {while (something) {...}})과 같은 것이 필요하다고 생각합니다. ' – Grundy

답변

-2

우선 정적 방법, 특히 정적 근로자를 사용하지 마십시오.

나는 당신이 여전히 당신의 UI 스레드에 있다고 믿는다. (나는 당신이 준 코드를 기반으로 몇 가지 일반적인 가정을하고있다.) 자동으로 UI 스레드를 호출해야하는 Task<string>.Factory.StartNew(...)을 사용해보십시오.

진행 표시 줄을 작동 시키려면 발송자를 사용하고 UI 스레드로 다시 호출해야합니다.

+1

UI 스레드는 동기식입니다 (작업을 수행 할 때 UI가 멈추는 이유입니다). 새 작업을 시작할 때 TPL이 백그라운드 스레드를 자동으로 호출하여 UI를 응답 성있게 유지합니다. –

1

나는 async/await이 실제로 어떻게 작동하는지 완전히 오해하고 있다고 생각합니다. 실제로 코드를 다르게 말하지 않기 때문에 모든 코드가 UI 스레드에서 실행 중입니다. 즉, await (method)은 동기식으로 실행되기 때문에 무의미합니다.

async/await의 목적은 호출 코드가 awaitable 작업의 결과를 필요로하는 코드의 일부를 돌 때까지 처리를 계속 할 수있는 기회를 허용하는 것입니다. 귀하의 예제에서, 당신이 당신의 method 몸을 변경해야 귀하의 방법 서명이 유효하지 않기 때문에 실제로, 모든 코드가 될 수없는 awaitable Task

public Task method(string input, string output, string options, IProgress<int> progress) 
{ 
    return Task.Run(() => { 
     while(something) 
     { 
      //operations on input and output 

      if (progress != null) 
      { 
       progress.Report(percentage); 
      } 
     } 
    }); 
} 
+0

진행 상황을보고하기 전에 'Invoke'를 호출 할 이유가 없습니다. 'Progress' 클래스를 사용하는 전체적인 요점은 당신을 대신해 UI 스레드에 마샬링 작업을 관리한다는 것입니다. 'StartNew'보다는'Task.Run'을 사용해야합니다. – Servy

+0

@Servy 충분히 공정하게, 나는 '진행'이 자동적으로 이것을했다는 것을 몰랐다. 어쨌든 예제를 제거한 것은 불필요하게 응답을 부풀린 것입니다. – James

+0

또한 'MyMethod'에있는 모든 의견이 잘못되었습니다. 'Calculating ... '은'CalcSomething'이 실행되는 동안 일어나지 않습니다. 'await'은'CalcSomething'이 끝날 때까지 실행되지 않도록합니다. – Servy

관련 문제