0

I am having a little bit of trouble getting a ProgressBar to work. When I start it up, nothing happens and I can't see why?

I thought that this would start the task worker.RunWorkerAsync();

The below example should be able to be copied and pasted into a new solution and be run for testing if needed.

The XAML,

<Grid Margin="20">
    <ProgressBar 
        Height="60"
        Minimum="0" 
        Maximum="100"
        Value="{Binding Progress, Mode=OneWay}" 
        Visibility="{Binding ProgressVisibility}"/>
</Grid>

My code,

public partial class MainWindow : Window
{
    public ProggressbarViewModel PsVm { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        PsVm = new ProggressbarViewModel();
    }

    public class ProggressbarViewModel
    {
        public ProggressbarViewModel()
        {
            var worker = new BackgroundWorker();
            worker.DoWork += DoWork;
            worker.ProgressChanged += ProgressChanged;
            worker.RunWorkerAsync();
        }

        private int _progress;

        public int Progress
        {
            get { return _progress; }
            set
            {
                if (_progress == value) return;
                _progress = value;
                OnPropertyChanged();
            }
        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(100);
                _progress = i;
                OnPropertyChanged();
            }
        }

        private void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Progress = e.ProgressPercentage;
        }

        public event PropertyChangedEventHandler PropertyChanged;

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

Any help would be much appreciated.

EDIT: The question is is similar possibly a duplicate in that sense, however the linked answer did not solve my problem, like it states in the Duplicate banner.

KyloRen
  • 2,691
  • 5
  • 29
  • 59
  • Possible duplicate of [How to implement a progress bar using the MVVM pattern](https://stackoverflow.com/questions/3520359/how-to-implement-a-progress-bar-using-the-mvvm-pattern) – Clint Jul 09 '17 at 11:28
  • @Clint, yes I saw that thread. Does not help me much , as I don't know where I am going wrong. – KyloRen Jul 09 '17 at 11:31

1 Answers1

4

When you're not explicitly indicating source object for your bindings (by means of Binding.Source or Binding.RelativeSource properties), the framework uses (possibly inherited) value of DataContext of the target object as the source. The problem is that you don't assign your view-model to the DataContext property of any control. Thus, the source for the bindings resolves to null and nothing is showing on your progress bar.

To resolve your issue you should assign your view model to the DataContext of your MainWindow:

public MainWindow()
{
    InitializeComponent();
    PsVm = new ProggressbarViewModel();
    DataContext = PsVm;
}

If however you're planning on using different DataContext for your window, you can bind DataContext of ProgressBar:

<ProgressBar
    DataContext="{Binding Path=PsVm,
                          RelativeSource={RelativeSource AncestorType=local:MainWindow}}"
    (...) />

You could also modify particular bindings by prepending PsVm. to the value of Path and using RelativeSource, e.g.:

 Value="{Binding Path=PsVm.Progress,
                 RelativeSource={RelativeSource AncestorType=local:MainWindow},
                 Mode=OneWay}"

In that case however you'd have to modify each binding, so previous solutions are quicker and/or simpler.

As a side note, you might also want to change the way you're reporting progress - note that OnPropertyChanged in your DoWork method is not called from UI thread. The proper way to do it would be:

private void DoWork(object sender, DoWorkEventArgs e)
{
    var worker = (BackgroundWorker)sender;
    for (int i = 0; i < 100; i++)
    {
        Thread.Sleep(100);
        worker.ReportProgress(i); //This will raise BackgroundWorker.ProgressChanged
    }
}

Also, in order to support progress reporting, you should set WorkerReportsProgress to true on your worker, e.g.:

var worker = new BackgroundWorker { WorkerReportsProgress = true };
Grx70
  • 10,041
  • 1
  • 40
  • 55
  • I am going to mark this as solved and UV, due to everything working in the code. It seems I have Data-context issue I need to sort out. – KyloRen Jul 09 '17 at 13:22
  • Thanks Grx70, I got it working thanks to your help. The DataContext issue is solved. Cheers. – KyloRen Jul 09 '17 at 13:35