简体   繁体   English

使用ViewModel在WPF窗口中实现进度栏

[英]implementing progress bar in wpf window with viewmodel

I have wpf window ( MainWindow .cs) which has button and progress bar. 我有WPF窗口( MainWindow .cs),它具有按钮和进度条。

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 进度条也绑定到ViewModel中的CurrentProgress属性

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

MainWindowViewModel.cs 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. 在实现进度条时我错了的地方,我在DoWork方法中设置了断点,尽管第一个命令StartMyWork可以按预期工作,但它从未被击中。

First of all, remove your second command ICommand _InstigateWorkCommand; 首先,删除第二个命令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); 在执行第一个命令的方法(DoSomeDummyWork)中 ,删除这些lambda表达式行_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 DoWork方法也应该像这样

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. *仅提及RunWorkerCompleted事件将触发,无论bg如何。 thread completed - wheter it completed normally or an exception is thrown (cancel action). 线程已完成-正常完成还是抛出异常(取消操作)。 Although if you shut down application while the bg. 虽然如果您关闭应用程序的同时bg。 worker running the application will immediatly exit without waiting bg. 运行该应用程序的工作人员将立即退出,而无需等待bg。 thread to complete.* 线程完成。*

You'll need to activate your _InstigateWorkCommand with some kind of interaction or you'll never kick off the actual update. 您需要通过某种交互来激活_InstigateWorkCommand,否则您将永远不会开始实际的更新。 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. 如果您想停止使用_InstigateWorkCommand并在单击绑定到StartMyWork的按钮时将其启动,则需要将RunWorkerAsync代码从RelayCommand绑定上移一个级别。

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();
}

Oh, not full answer. 哦,还不完整。 As Maximus said, add _Worker.RunWorkerAsync() to the end of your DoSomeDummyWork method. 如Maximus所说,在您的DoSomeDummyWork方法的末尾添加_Worker.RunWorkerAsync() Then: 然后:

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

Not _CurrentProgress , but CurrentProgress . 不是_CurrentProgress ,而是CurrentProgress It will notify your ProgressBar about changes. 它将通知您的ProgressBar有关更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM