0

Before I get into the details here, I'm still in what I would consider to be the "learning" phase of my C#/WPF journey... so apologies if what I'm asking here is stupidly obvious... I have a small application (WPF, .NET Framework 4.8) that does the following:

  • read a list of values
  • do something for each value in the list

I am trying to do this with a BackgroundWorker so that I can report back to the UI as the list is being processed, preferably with a progress bar.

For the moment, the DoWork method just has some code in there to indicate that it's actually going through the process as expected and so that I could check that all the UI is updating as expected before I put the actual "what I want it to do" in there.

It seems that all the properties are updating as expected, but the UI (i.e. the progress bar) just doesn't move. And I have checked that the data context in the XAML is set correctly (both in the XAML and in the Code-Behind).

In my XAML I have the following:

<ProgressBar x:Name="ProgressBar"
             Width="740"
             Height="20"
             Background="Transparent"
             Foreground="#008DEB"
             Grid.Row="3"
             Minimum="0"
             Maximum="100"
             Value="{Binding ProgressBarIndicator}"/>

And in my class containing all my methods/properties etc, I have:

private int _measurementProgress;
        public int MeasurementProgress
        {
            get { return _measurementProgress; }
            set
            {
                _measurementProgress = value;
                OnPropertyChanged();
            }
        }

        private int _progressBarIndicator;
        public int ProgressBarIndicator
        {
            get { return _progressBarIndicator; }
            set 
            { 
                _progressBarIndicator = value;
                OnPropertyChanged();
            }
        }


public void StartMeasurements(string ipAddress)
        {
            TotalMeasurementsInList = CommandsList.Count;
            MeasurementProgress = 0;

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

        public void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            foreach (var command in CommandsList)
            {
                MessageBox.Show(String.Format("Measuring Sample: {0}",command.SampleName),"Measuring Sample");
                measurementWorker.ReportProgress((int)((double)(MeasurementProgress / (double)TotalMeasurementsInList)*100));
                Thread.Sleep(command.DelayTime*1000);
            }

        }

        public void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            MeasurementProgress++;
            MessageBox.Show(String.Format("Progress is {0}%", e.ProgressPercentage.ToString()));
            ProgressBarIndicator = e.ProgressPercentage;
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ProgressBarIndicator = 100;
            MessageBox.Show("Measurements are completed","Finished");
        }

The "OnPropertyChanged()" method is inside my ObservableObject class, and the above class is set to inherit from this ObservableObject class. The ObservableObject class looks like this:

public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyname = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }
    }

By placing break-points in strategic places, I can confirm that the value of MeasurementProgress does indeed increment as one would expect, as does the value of ProgressBarIndicator. This was double-confirmed by the MessageBox in the worker_ProgressChanged method as it does indeed display the appropriate percentage value.

Annoyingly, what would appear to me to be exactly the same code is working as expected in another part of the application. The code here is more or less a copy/paste from there... but I just can't see what I'm doing wrong.

Any help or pointers where I could look to try and debug this appreciated.

Many thanks

Colin

  • Anything in the `DoWork` method is in the background thread and should never make any UI related calls. You should remove the call to `MessageBox` from `DoWork`. Anything UI related should be made via `ProgressChanged` or `RunWorkerRelated`. – Rick Davin Oct 25 '22 at 13:49
  • 1
    You may want to take a look at [this](https://stackoverflow.com/q/16363263/1136211) and similar questions. BackgroundWorker is obsolete, don't waste your time with it. Better learn how to run and await an async Task that reports via IProgress. – Clemens Oct 25 '22 at 14:06
  • The problem is not with `BackgroundWorker`. Trace down how, what, and when you bind values to the `ProgressBar` Inside the `ProgressBarIndicator` setter, consider issuing a `NotifyPropertyChange("ProgressBarIndicator")`. And you really should heed @Clemens advice and replace the antiquated, obsolete `BackgroundWorker` component with `async Task` instead. – Rick Davin Oct 25 '22 at 14:37

0 Answers0