0

I have wpf window (MainWindow.cs) which has button and progress bar.

Button is bound to command inside my viewmodel

<Button Command="{Binding StartMyWork}" Content="Run" Width="200" Height="50"/>

progress bar is bound to CurrentProgress property also in viewmodel

<ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}"  Width="400"/>

MainWindowViewModel.cs

private ICommand _StartMyWork;
public ICommand StartMyWork;
{ 
    get {
         if (_StartMyWork == null) {
                _StartMyWork = new RelayCommand(
                       x => this.DoSomeDummyWork(this.MySelectedComboValue)
                );
          }
          return _StartMyWork;
     }
}

private void DoSomeDummyWork(string mySelectedComboProp)
{
    // here I want to simulate some work
    // and make ui responsive and introduce progressbar    
}

I was thinking using this answer

So I added in the same viewmodel

private ICommand _InstigateWorkCommand;
private double _CurrentProgress;
private BackgroundWorker _Worker;

private void DoSomeDummyWork(string mySelectedComboProp)
{
    // here I want to simulate some work
    // and make ui responsive and introduce progressbar
     _InstigateWorkCommand = new RelayCommand(x => _Worker.RunWorkerAsync(),  x => !_Worker.IsBusy);
     _Worker = new BackgroundWorker();
     _Worker.DoWork += DoWork;
     _Worker.ProgressChanged += this.ProgressChanged;   
}

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

public double CurrentProgress
{
    get { return _CurrentProgress; }
    private set {
         if (_CurrentProgress != value){
            _CurrentProgress = value;
            OnPropertyChanged("CurrentProgress");
         }
    }
}

private void DoWork(object sender, DoWorkEventArgs e)
{
   for (int i = 0; i < 10; i++) {
       Thread.Sleep(1000);
       _CurrentProgress = i;
   }
}

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

Where I'm wrong in implementing progress bar, I set breakpoint in DoWork method which is never hitted, although first command StartMyWork works as expected.

Community
  • 1
  • 1
user1765862
  • 13,635
  • 28
  • 115
  • 220
  • 1
    Add _Worker.RunWorkerAsync(), you never call _Worker.ReportProgress(value) so ProgressChanged will never be invoked. – Maximus Aug 29 '14 at 19:51
  • please can you be specific, I already have _Worker.RunWorkerAsync(), .. inside DoSomeDummyWork method. – user1765862 Aug 29 '14 at 19:53
  • I dont know why you're being so rude, he's right, it's getting called in his lamba right at the top of DoSomeDummywork in the view model, and he's got no edits on the question. – C Bauer Aug 29 '14 at 20:16
  • I think he just kept it in the InstigateWork relaycommand by mistake. – C Bauer Aug 29 '14 at 20:27
  • `if _StartMyWork;== null)` isn't going to compile. Please post correct code to avoid all sorts of confusion. – H H Aug 29 '14 at 21:05

3 Answers3

4

First of all, remove your second command ICommand _InstigateWorkCommand; you dont need it, at least for now, it just makes you confuse.

Inside your method (DoSomeDummyWork) which first command executes remove those lambda expression line _InstigateWorkCommand = new RelayCommand(x => _Worker.RunWorkerAsync(), x => !_Worker.IsBusy);
and put this

 _Worker = new BackgroundWorker();
 _Worker.WorkerReportsProgress = true;
 _Worker.DoWork += DoWork;                        
 _Worker.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
_Worker.RunWorkerAsync();

also DoWork method should look like this

private void DoWork(object sender, DoWorkEventArgs e)
{
  for (int i = 0; i < 10; i++)
   {
    Thread.Sleep(1000);
    _Worker.ReportProgress(i*(100/10));          
  }            
}

private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    _CurrentProgress = e.ProgressPercentage;
    OnPropertyChanged("CurrentProgress");
}

Also you should now add method which will be called once iteration is completed

void workerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    MessageBox.Show("Complete!");
}

and wire this method

_Worker.RunWorkerCompleted += 
      new RunWorkerCompletedEventHandler(workerCompleted);

*Just to mention that RunWorkerCompleted event fires, no matter how the bg. thread completed - wheter it completed normally or an exception is thrown (cancel action). Although if you shut down application while the bg. worker running the application will immediatly exit without waiting bg. thread to complete.*

BobRock
  • 3,477
  • 3
  • 31
  • 48
  • key line is OnPropertyChanged("CurrentProgress") i believe, what is the difference between having in the progresschanged function vs having like original questions in the property constructor. obviously your one works and other one doesnt work but why? does it not trigger when property changes? – Emil Jan 22 '15 at 11:39
1

You'll need to activate your _InstigateWorkCommand with some kind of interaction or you'll never kick off the actual update. If you want to instead stop using _InstigateWorkCommand and just kick it off when you click the button bound to StartMyWork, than you'll need to move the RunWorkerAsync code up a level out of the RelayCommand binding.

Ex:

private void DoSomeDummyWork(string mySelectedComboProp)
{
    // here I want to simulate some work
    // and make ui responsive and introduce progressbar
     _Worker = new BackgroundWorker();
     _Worker.DoWork += DoWork;
     _Worker.ProgressChanged += this.ProgressChanged; 
     _Worker.RunWorkerAsync();
}
C Bauer
  • 5,003
  • 4
  • 33
  • 62
0

Oh, not full answer. As Maximus said, add _Worker.RunWorkerAsync() to the end of your DoSomeDummyWork method. Then:

private void DoWork(object sender, DoWorkEventArgs e)
{
   for (int i = 0; i < 10; i++) {
       Thread.Sleep(1000);
       _CurrentProgress = i;
   }
}

Not _CurrentProgress, but CurrentProgress. It will notify your ProgressBar about changes.

cdmnk
  • 314
  • 1
  • 11
  • He already set up the runworkerasync in a relay command at the top of his viewmodel. – C Bauer Aug 29 '14 at 20:18
  • As I understand, if he retained old command, new would not be called. If he changed main command to this, whole DoSomeDummyWork would not be executed – cdmnk Aug 29 '14 at 20:23