Search code examples
wpfmultithreadingbackgroundworker

ProgressChanged not updating progressbar


I have an issue with ProcessChanged. It's fired in the code (when I'm looking in the debugger) but it doesn't update in my mainscreen where the progressbar is located.

The initialisation of the BackgroundWorker

private void Import_Click(object sender, RoutedEventArgs e)
    {
        progressbarImport.Value = 0;

        int max = DatagridZegrisWeekImport.Items.Count;

        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();
    }

The DoWork

void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        var manager = new ZegrisReadToDB();

        int progressPercentage = 0;
        int max = DatagridZegrisWeekImport.Items.Count;

        for (int i = 0; i < max; i++)
        {
            this.Dispatcher.Invoke(() =>
            {
                DatagridZegrisWeekImport.SelectedIndex = i;
                var selecteditem = DatagridZegrisWeekImport.SelectedItem as ZegrisWeekDataImport;
                string exist = manager.CheckExist2(selecteditem.Artikelnummer, selecteditem.Jaar);
                if (exist == "")
                {
                    insert statement;

                    progressPercentage = Convert.ToInt32(((double)i / max) * 100);
                    (sender as BackgroundWorker).ReportProgress(progressPercentage);
                    Thread.Sleep(100);
                }
                else
                {
                    update statement

                    progressPercentage = Convert.ToInt32(((double)i / max) * 100);
                    (sender as BackgroundWorker).ReportProgress(progressPercentage);
                    Thread.Sleep(100);
                }
            });
        }
    }

The ProgressChanged

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Application.Current.Dispatcher.Invoke(() =>
        this.progressbarImport.Value = e.ProgressPercentage);
    }

As you may see, I have already tried a couple of solutions found on this forum, but none seem te be working. It's the first time I'm using BackgroundWorker and somewhere I lost my train of thought.


Solution

  • If you are intent on using the BackgroundWorker then try the following code

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var manager = new ZegrisReadToDB();
    
            int progressPercentage = 0;
    
            // use the source list if you have it available, rather than casting here
            List<ZegrisWeekDataImport> items = DatagridZegrisWeekImport.Items.Cast<ZegrisWeekDataImport>().ToList();
            var max = items.Count;
    
            for (int i = 0; i < max; i++)
            {                    
                var item = items[i];
    
                string exist = manager.CheckExist2(item.Artikelnummer, item.Jaar);
    
                if (exist == "")
                {
                    insert statement;
    
                    progressPercentage = Convert.ToInt32(((double)i / max) * 100);
                    (sender as BackgroundWorker).ReportProgress(progressPercentage);
                }
                else
                {
                    update statement
    
                    progressPercentage = Convert.ToInt32(((double)i / max) * 100);
                    (sender as BackgroundWorker).ReportProgress(progressPercentage);                       
                }
            }
        }
    
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressbarImport.Value = e.ProgressPercentage);
        }
    

    If you have control of your ZegrisReadToDB class it would be beneficial to make this async if you can. Below is a version that uses async/await

        // bind you progress bar to this
        public double Progress { get; set; } // raise property changed
    
        // bind your datagrid to this property
        public List<ZegrisWeekDataImport> Items {get;set;} = new List<ZegrisWeekDataImport>();
    
        private async void Import_Click(object sender, RoutedEventArgs e)
        {
            await DoWork();
        }
    
        public async Task DoWork()
        {
            for (int i = 0; i < Items.Count; i++)
            {
                var item = Items[i];
    
                string exist = await manager.CheckExist2(item.Artikelnummer, item.Jaar);
    
                if (exist == "")
                {
                    await insert statement
                }
                else
                {
                    await update statement
                }
    
                Progress = (double)i / max) * 100; 
            }
        }