从线程- MVVM更新进度条

本文关键字:更新 MVVM 线程 | 更新日期: 2023-09-27 17:49:45

我是MVVM模式的新手。我有一个问题,从另一个线程更新进度条。

视图。Xaml

<ProgressBar Value="{Binding ProgressBarValue}">

ViewModel.cs

public int ProgressBarValue 
{
            get
            {
                return status;
            }
            set
            {
                this.status = value;
                this.RaisePropertyChanged(() => this.ProgressBarValue);
            }
}

Thread th;
private void OnOk()
{
   th=new Thread(new ThreadStart(StartProcess));
}
private void StartProcess()
{
  utilityclass.DoWork();
}

UtilityClass.cs

public void DoWork()
{
   for(i=0;i<100;i++)
   {
      //dosomething
   }
}

我的问题是如何将DoWork方法的进度更新到视图?我通过使用后台worker类找到了很多解决方案。但由于某些原因,我不能遵循这些方法。我真的需要一个帮助。

从线程- MVVM更新进度条

我只需将ProgressChanged事件添加到UtilityClass中。

class UtilityClass
{
    public event EventHandler<ProgressChangedEventHandler> ProgressChanged;
    public class ProgressChangedEventHandler : EventArgs
    {
        public int Progress
        {
            get;
            private set;
        }
        public ProgressChangedEventHandler(int progress)
        {
            Progress = progress;
        }
    }
    public void DoWork()
    {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(300);
            if (ProgressChanged != null)
                ProgressChanged(this, new ProgressChangedEventHandler(i));
        }
    }
}

然后你可以在你的视图模型中订阅这个事件,并在每次事件引发时更新属性值。

    public ShellViewModel()
    {
        utilityclass = new UtilityClass();
        utilityclass.ProgressChanged += utilityclass_ProgressChanged;
    }
    void utilityclass_ProgressChanged(object sender, UtilityClass.ProgressChangedEventHandler e)
    {
        ProgressBarValue = e.Progress;
    }

哦,注意你应该实际启动线程!我假设这个方法可能需要是公共的。

    public void OnOk()
    {
        th = new Thread(new ThreadStart(StartProcess));
        th.Start();
    }

也可以在用户关闭表单时中止此线程。

这段代码将取决于你的MVVM框架。在这里,我使用从Caliburn派生的视图模型。微的Screen类,所以我可以覆盖OnDeactivate方法和关闭线程那里。

    protected override void OnDeactivate(bool close)
    {
        if (close)
        {
            th.Abort();
        }
    }

根据注释中的建议,您应该使用Dispatcher来更新ui绑定值。

在你的DoWork方法中,你应该调用Ui组件的适当Dispatcher来调用Ui线程中的更新进程。因为你使用MVVM,你的ViewModel不应该知道任何关于UI组件,所以你可以使用

Application.Current.Dispatcher.Invoke( () => { ProgressBarValue = i; } );

这将更新你的进度条。

另外,看看更常见的INotifyPropertyChanged实现,比如ReSharper的值检查是否真的发生了变化。