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

-Actualizado - 14/10 También pregunté estopregunta

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 hacer que se ejecute y anime mientras mi hilo de fondo ejecuta mi largo proceso hacia la base de datos y luego invoca un evento de formulario cerrado.

El trabajador de fondo se configura aquí

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

Entonces los delegados añadieron 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 de la 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 fondo trabaja es

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 estoy configurada como Indeterminable, por lo que simplemente se "balancea" a través de mi formulario ProgressDialoge para mostrar al usuario que algo está sucediendo. He utilizado la parte de reportero del trabajo en segundo plano porque creo que tiene acceso al subproceso de la ventana principal y espero que el método de invocación se llame desde el subproceso de la ventana principal, pero no estoy realmente 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 ProgressDialog y su clase

<Window x:Class="Test_Read_CSV.ProgressDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Progress Dialog" Height="115" Width="306" Name="ProgressPopup">
<Grid>
    <ProgressBar Height="31" HorizontalAlignment="Left" Margin="12,33,0,0" Name="progressBar1" VerticalAlignment="Top" Width="250" />
    <TextBox Height="23" HorizontalAlignment="Left" Margin="7,4,0,0" Name="tbEvent" VerticalAlignment="Top" Width="254" IsReadOnly="True" IsEnabled="False" />
</Grid>

clase

/// <summary>
/// Interaction logic for ProgressDialog.xaml
/// </summary>
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 realizado una serie de tutoriales sobre trabajo en segundo plano e incluso algunos en subprocesos, pero parece que no puedo obtener el resultado que deseo

La idea es que tengo dos procesos largos en los que obtengo un clon de datos de mi bd remoto o estoy actualizando la base de datos de mi aplicación wpf (.net 4). Mientras el proceso se está ejecutando, quiero un control de la barra de progreso y actualizarlo, por la razón obvia de dejar en claro que se está realizando algún trabajo. Así que hice las rutinas de progreso de informe habituales en el trabajador de fondo y funciona ... Sin embargo, en mi hilo de dowork tengo este comando

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

Esto es 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 todavía se ve congelada y se ha estrellado!

Así que todo lo que quiero hacer es al inicio de la llamada al trabajo en segundo plano establecer una barra de progreso en ejecución y dejarla en ejecución hasta el final de la tarea. ¡Esto es todo lo que necesito hacer para terminar mi primer proyecto y después de tres días todavía no puedo entenderlo!

Así que he intentado el seguimiento

En el progreso de bw cambiado y en la clase de ventana principal.

 this.progressBar2.IsIndeterminate = true;

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

Luego creé otro trabajador de fondo para actualizar el progressbar2, que estaba vinculado a un botón en la ventana principal estaba bien, pero tan pronto como intenté usarlo desde el otro trabajador de fondo o desde la clase de la ventana principal no funcionó hasta el dowork hilo había completado en el primer trabajador de fondo

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

Entonces, ¿alguien puede ayudarme? Puedo adivinar que es algo que ver con subprocesos y trabajar en el subproceso incorrecto, etc. Pero no tengo idea de lo que hago al respecto.

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

Ian

Respuestas a la pregunta(1)

Su respuesta a la pregunta