使用viewmodel在wpf窗口中实现进度条

时间:2014-08-29 19:42:30

标签: c# .net wpf mvvm

我有wpf窗口(MainWindow。cs),它有按钮和进度条。

按钮绑定到我的viewmodel

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

进度条也在viewmodel

中绑定到CurrentProgress属性
<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    
}

我在考虑使用this answer

所以我添加了相同的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;
}

我在实施进度条时出错了,我设置了断点 虽然第一个命令StartMyWork按预期工作,但DoWork方法永远不会被命中。

3 个答案:

答案 0 :(得分:4)

首先, 删除你的第二个命令ICommand _InstigateWorkCommand;你不需要它,至少现在,它只会让你感到困惑。

在第一个命令执行的方法(DoSomeDummyWork)中删除那些lambda表达式行 _InstigateWorkCommand = new RelayCommand(x =&gt; _Worker.RunWorkerAsync(),x =&gt;!_ Worker.IsBusy);
并把这个

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

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

此外,您现在应该添加一旦迭代完成后将被调用的方法

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

并连接此方法

_Worker.RunWorkerCompleted += 
      new RunWorkerCompletedEventHandler(workerCompleted);

*只要提及 RunWorkerCompleted 事件就会触发,无论bg如何。线程已完成 - 正常完成或抛出异常(取消操作)。虽然如果你关闭应用程序而bg。运行应用程序的工作人员将立即退出而不等待bg。线程完成。*

答案 1 :(得分:1)

您需要通过某种互动来激活您的_InstigateWorkCommand,否则您将永远不会启动实际更新。如果您想要停止使用_InstigateWorkCommand并在单击绑定到StartMyWork的按钮时启动它,那么您需要将RunWorkerAsync代码移出RelayCommand绑定的某个级别。

例如:

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

答案 2 :(得分:0)

哦,不是完整的答案。正如Maximus所说,将_Worker.RunWorkerAsync()添加到DoSomeDummyWork方法的末尾。然后:

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

不是_CurrentProgress,而是CurrentProgress。它会通知您的ProgressBar有关更改。