¿Cómo implementar correctamente un BackgroundWorker con actualizaciones de ProgressBar?

-Actualizado: 14/10 también hizo esta pregunta

Para dar una idea clara de lo que está sucediendo y teniendo en cuenta los comentarios y de este artículo aquí

Lo que realmente quiero hacer ahora es invocar un nuevo formulario con una barra de progreso y ejecutarlo y animarlo mientras mi hilo de fondo ejecuta mi largo proceso hacia la base de datos y luego invocar un evento de formulario cerrado.

El trabajador de fondo está configurado aquí

public partial class MainWindow : Window { //Declare background workers BackgroundWorker bw = new BackgroundWorker(); BackgroundWorker bwLoadCSV = new BackgroundWorker(); BackgroundWorker bwProgressBar = new BackgroundWorker(); 

Entonces los delegates agregaron aquí

  public MainWindow() { bwLoadCSV.WorkerReportsProgress = true; bwLoadCSV.WorkerSupportsCancellation = true; bwLoadCSV.DoWork += new DoWorkEventHandler(bwLoadCSV_DoWork); bwLoadCSV.ProgressChanged += new ProgressChangedEventHandler(bwLoadCSV_ProgressChanged); bwLoadCSV.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwLoadCSV_RunWorkerCompleted); 

La llamada se hace aquí desde la clase ventana principal

  private void CSV_Load_Click(object sender, RoutedEventArgs e) ///Function to read csv into datagrid /// { //Turn Cursor to wait System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor; //Test connection to sql server if (CHHoursDataProvider.IsDatabaseOnline() == false) { System.Windows.Forms.MessageBox.Show("Can not establish contact with sql server" + "\n" + "Contact IT", "Connection Error"); //Set UI picture return; } //Set a control to update the user here tbLoadDgStat.Visibility = Visibility.Visible; tbLoadDgStat.Text = "Getting data templete from Database..."; string FilePath = txFilePath.Text; if (bwLoadCSV.IsBusy != true) { //load the context object with parameters for Background worker bwCSVLoadContext Context = new bwCSVLoadContext(); Context.Site = cBChSite.Text; Context.FilePath = txFilePath.Text; Context.FileName = fileTest; Context.Wageyear = cbWageYear.Text; Context.Startdate = ((DateTime)dpStartDate.SelectedDate); Context.Enddate = ((DateTime)dpEndDate.SelectedDate); bwLoadCSV.RunWorkerAsync(Context); } 

El trabajador de base trabaja

 private void bwLoadCSV_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; bwCSVLoadContext Context = e.Argument as bwCSVLoadContext; worker.ReportProgress((10)); if ((worker.CancellationPending == true)) { e.Cancel = true; } else { // Perform a time consuming operation and report progress load csv into datagrid. 

Para informar el trabajo de fondo, hago esto. Aquí es donde estoy tratando de cargar un nuevo formulario llamado ProgressDialog que tiene una barra de progreso, que bash configurar como Indeterminable, de modo que solo “agite” en mi formulario ProgressDialoge para mostrarle al usuario que algo sigue sucediendo. He usado la parte de reportero del trabajo de fondo porque creo que tiene acceso al hilo de la ventana principal y espero que el método de invocación se llame desde el hilo de la ventana principal, pero no estoy muy seguro

Aquí está el reportero

  private void bwLoadCSV_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.Dispatcher.Invoke((MethodInvoker)delegate { tbLoadDgStat.Visibility = Visibility.Visible; }); //tbLoadDgStat.Visibility = Visibility.Visible; //this.progressBar1.Value = e.ProgressPercentage;//This works but pauses on long steps if (e.ProgressPercentage == 10) { //Try to open a new form with a class ProgressDialog and set the progressbar // on the frm to IsIndeterminate=true //THIS IS NOT WORKING this.Dispatcher.BeginInvoke (new Action(() => { ProgressDialog progressDialog = new ProgressDialog(); progressDialog.SetIndeterminate(true); })); //this updates the main form OK this.Dispatcher.Invoke((MethodInvoker)delegate { tbLoadDgStat.Text = "Getting data templete from Database..."; }); } else if (e.ProgressPercentage == 20) { this.Dispatcher.Invoke((MethodInvoker)delegate { tbLoadDgStat.Text = "Data template retrieved..."; }); } else { if (e.ProgressPercentage % 10 == 0) { this.Dispatcher.Invoke((MethodInvoker)delegate { tbLoadDgStat.Text = "Adding Data..." + e.ProgressPercentage.ToString() + "%"; }); } } 

Por último, el xaml para el formulario de progresoDialog y su clase

      

clase

 ///  /// Interaction logic for ProgressDialog.xaml ///  public partial class ProgressDialog : Window { public ProgressDialog() { WindowStartupLocation = WindowStartupLocation.CenterScreen; InitializeComponent(); } public ProgressDialog(String Purpose) { InitializeComponent(); tbEvent.Text = Purpose; WindowStartupLocation = WindowStartupLocation.CenterScreen; } public void UpdateProgress(int progress) { progressBar1.Dispatcher.BeginInvoke( new Action(() => { progressBar1.Value = progress; } )); } public void SetIndeterminate(bool isIndeterminate) { progressBar1.Dispatcher.BeginInvoke( new Action(() => { if (isIndeterminate) { progressBar1.IsIndeterminate = true; } else { progressBar1.IsIndeterminate = false; } } )); } } } 

He leído y he hecho una serie de tutoriales sobre trabajadores en segundo plano e incluso algunos sobre hilos, pero parece que no puedo obtener el resultado que quiero

La idea es que tengo dos procesos largos en los que obtengo un clon de tabla de datos de mi BD remoto o estoy actualizando el DB de mi aplicación wpf (.NET 4). Mientras el proceso se está ejecutando, quiero un control de barra de progreso y actualizarlo, por la obvia razón de dejar en claro que algo de trabajo está sucediendo. Así que hice las rutinas de progreso de informes habituales en el trabajador de segundo plano y funciona …. Sin embargo, en mi hilo dowork tengo este comando

 CHHoursDataProvider CH = new CHHoursDataProvider(); oTable = CH.CloneCHHours(); 

aquí donde la comunicación con db es y este comando toma unos buenos 60 – 90 segundos en una conexión remota vpn así que incluso si hago esto

 CHHoursDataProvider CH = new CHHoursDataProvider(); worker.ReportProgress((10)); oTable = CH.CloneCHHours(); worker.ReportProgress((20)); 

¡La ventana principal aún se ve congelada y se ha estrellado!

Así que todo lo que quiero hacer es al inicio de la llamada al trabajo de fondo que se establezca una barra de progreso ejecutándose y dejarla en funcionamiento hasta el final de la tarea. ¡Esto es todo lo que tengo que hacer para terminar mi primer proyecto y después de tres días todavía no puedo entenderlo!

Así que he intentado seguir

En el progreso de bw cambió y en la clase ventana principal

  this.progressBar2.IsIndeterminate = true; 

Sin embargo, la animación no comienza hasta que el hilo Dowork ha terminado.

Luego creé otro background worker para actualizar la barra de progreso2, que enlazaba con un botón en la ventana principal estaba bien, pero tan pronto como traté de usarlo desde el otro trabajador de fondo o desde la clase de ventana principal no funcionó hasta que el dowork hilo se había completado en el primer trabajador de fondo

¡Luego traté de seguir un método de invocación, pero REALMENTE me perdí de eso!

Entonces, ¿alguien puede ayudarme? Puedo adivinar que tiene que ver con enhebrar y trabajar con el hilo equivocado, etc. pero lo que hago al respecto no lo tengo.

Puedo publicar más código según sea necesario

Ian

Como no ha mostrado su código completo de BackgroundWorker , no puedo decir si lo ha implementado correctamente. Como tal, todo lo que puedo hacer es mostrarle un ejemplo simple de actualización de un control ProgressBar :

UserControl XAML:

    

MainWindow XAML:

    

Código de UserControl detrás:

 using System.ComponentModel; using System.Threading; using System.Windows; using System.Windows.Controls; namespace WpfApplication1.Views { public partial class TestView : UserControl { private BackgroundWorker backgroundWorker = new BackgroundWorker(); public TestView() { InitializeComponent(); backgroundWorker.WorkerReportsProgress = true; backgroundWorker.ProgressChanged += ProgressChanged; backgroundWorker.DoWork += DoWork; // not required for this question, but is a helpful event to handle backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; } private void UserControl_Loaded(object sender, RoutedEventArgs e) { backgroundWorker.RunWorkerAsync(); } private void DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < = 100; i++) { // Simulate long running work Thread.Sleep(100); backgroundWorker.ReportProgress(i); } } private void ProgressChanged(object sender, ProgressChangedEventArgs e) { // This is called on the UI thread when ReportProgress method is called progressBar.Value = e.ProgressPercentage; } private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // This is called on the UI thread when the DoWork method completes // so it's a good place to hide busy indicators, or put clean up code } } }