2010-06-10 3 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

Индикатор прогресса обновляется, если я выполняю фактическую работу или выполняю несколько операций ввода-вывода в этом цикле. Хотя мне не приходилось объединять методы, но слияние их не имеет значения. – Syler

+0

Правильно, очень сложная петля обновления была вашей проблемой. В реальной ситуации рассмотрим: 'if (p% 10 == 0) bgWorker.ReportProgress (p);', вы нацелены на 10 - 100 обновлений. –

3

Posibility:
Dispatcher.BeginInvoke() является асинхронной операцией. Так как это так, вы можете попробовать ударить его снова, прежде чем он завершит свою работу. Чтобы проверить, не является ли эта проблема, попробуйте Dispatcher.Invoke(), которая является синхронной.

В качестве возможного обходного пути, если вы просто хотите обновить индикатор выполнения, событие BackgroundWorker ProgressChanged могло бы сделать это без использования явного диспетчера ,

+0

Да, хороший улов, я пропустил это. Изменит мой ответ. –