2010-06-10 5 views
3
namespace WpfApplication1 
{ 
/// <summary> 
/// Interaction logic for Window1.xaml 
/// </summary> 
public partial class Window1 : Window 
{ 
    BackgroundWorker bgWorker; 
    Action<int> myProgressReporter; 

    public Window1() 
    { 
     InitializeComponent(); 
     bgWorker = new BackgroundWorker(); 
     bgWorker.DoWork += bgWorker_Task; 
     bgWorker.RunWorkerCompleted += myWorker_RunWorkerCompleted; 

     // hook event to method 
     bgWorker.ProgressChanged += bgWorker_ReportProgress; 

     // hook the delegate to the method 
     myProgressReporter = updateProgress; 

     bgWorker.WorkerReportsProgress = true; 

    } 

    private void myWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) 
    { 
     object result; 
     result = e.Result; 
     MessageBox.Show(result.ToString()); 
     progressBar1.Value = 0; 
     button1.IsEnabled = true; 
    } 

    private void bgWorker_ReportProgress(object sender, ProgressChangedEventArgs e) 
    { 
     System.Windows.Threading.Dispatcher disp = button1.Dispatcher; 
     disp.BeginInvoke(myProgressReporter,e.ProgressPercentage); 
     //Dispatcher.BeginInvoke(myProgressReporter, DispatcherPriority.Normal, e.ProgressPercentage); 
    } 

    private void updateProgress(int progressPercentage) 
    { 
     progressBar1.Value = progressPercentage; 
    } 

    private void bgWorker_Task(Object sender, DoWorkEventArgs e) 
    { 
     int total = 1000; 
     for (int i = 1; i <= total; i++) 
     { 
      if (bgWorker.WorkerReportsProgress) 
      { 
       int p = (int)(((float)i/(float)total) * 100); 
       bgWorker.ReportProgress(p); 
      } 
      Thread.Sleep(1); // Without Thread.Sleep(x) the main thread freezes or gives stackoverflow exception, 
     } 

     e.Result = "Completed"; 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    {    
     if(!bgWorker.IsBusy) 
      bgWorker.RunWorkerAsync("This is a background process"); 
     button1.IsEnabled = false; 
    } 
} 
} 
+0

궁금한 점 : TerrorAustralis의 조언을 따르고 ReportProgress를 동기식으로 수행하는 경우 여전히 절전 모드가 필요합니까? 일종의 내부 최적화일지도 모릅니다. 모든 비동기 호출이 차단 된 후에 실행됩니다. –

답변

5

귀하의 (인공적인) 시나리오에서 1000 스레드 요청을 메인 스레드로 보내주기 때문에
유휴 루프를 수행 할 시간이 없습니다 (화면 업데이트를 수행하는 데 필요함).

(TerrorAustralis 덕택에) bgWorker_ReportProgress 및 myProgressReporter 메소드를 병합해야합니다. 이제 stackoverflow의 가능한 원인 인 두 번을 동기화합니다. 의 UpdateProgress 이벤트를 파견하는 것은 BackgroundWorker에의 주요 특징 중 하나입니다

private void bgWorker_ReportProgress(object sender, ProgressChangedEventArgs e) 
{ 
    //System.Windows.Threading.Dispatcher disp = button1.Dispatcher; 
    //disp.BeginInvoke(myProgressReporter,e.ProgressPercentage); 
    progressBar1.Value = progressPercentage; // safe because we're on the main Thread here 
} 
+0

실제 작업을하거나 루프에서 일부 IO를 수행하면 progressbar가 잘 업데이트됩니다. 메소드를 병합하지 않아도되지만 병합하지 않아도 차이는 없습니다. – Syler

+0

맞습니다. 매우 빡빡한 업데이트 루프가 문제였습니다. 실제 상황에서는 다음을 고려하십시오 :'(p % 10 == 0) bgWorker.ReportProgress (p);', 총 10 - 100 건의 업데이트를 목표로합니다. –

3

있는 posibility :
Dispatcher.BeginInvoke()가 비동기 작업입니다. 이 경우 작업이 완료되기 전에 다시 시도 할 수 있습니다. 이것이 문제인지 확인하려면, 동기 인 Dispatcher.Invoke()를 시도하십시오.

가능한 해결 방법은 진행률 막대를 업데이트하기 만하면 backgroundWorker ProgressChanged 이벤트가 명시 적 디스패처를 사용하지 않고이 작업을 수행 할 수 있습니다. .

+0

예, 좋은 캐치, 나는 그것을 놓쳤습니다. 내 대답을 편집 할 것입니다. –

관련 문제