从线程 MVVM 更新进度条
Update progressbar from thread- MVVM
我是 MVVM 模式的新手。我在从另一个线程更新进度条时遇到问题。
View.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 方法的进度更新到视图?我通过使用后台工作者 class 找到了很多解决方案。但由于某些原因,我无法遵循这些方法。我真的需要帮助。
根据评论中的建议,您应该使用 Dispatcher
来更新 ui 绑定值。
在您的方法 DoWork 中,您应该调用 Ui 组件的适当 Dispatcher
来调用 UI 线程中的更新过程。由于您使用 MVVM,因此您的 ViewModel 不应该知道任何关于 UI 组件的信息,因此您可以使用
Application.Current.Dispatcher.Invoke( () => { ProgressBarValue = i; } );
这将更新您的进度条。
此外,查看更常见的 INotifyPropertyChanged 实现,例如来自 ReSharper 的实现,其中包含检查值是否真正更改的实现。
我只需将 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.
public void OnOk()
{
th = new Thread(new ThreadStart(StartProcess));
th.Start();
}
您可能还想在用户关闭表单时中止此线程。
此代码将取决于您的 MVVM 框架。这里我使用从 Caliburn.Micro 的 Screen
class 派生的视图模型,因此我可以重写 OnDeactivate
方法并在那里关闭线程。
protected override void OnDeactivate(bool close)
{
if (close)
{
th.Abort();
}
}
我是 MVVM 模式的新手。我在从另一个线程更新进度条时遇到问题。
View.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 方法的进度更新到视图?我通过使用后台工作者 class 找到了很多解决方案。但由于某些原因,我无法遵循这些方法。我真的需要帮助。
根据评论中的建议,您应该使用 Dispatcher
来更新 ui 绑定值。
在您的方法 DoWork 中,您应该调用 Ui 组件的适当 Dispatcher
来调用 UI 线程中的更新过程。由于您使用 MVVM,因此您的 ViewModel 不应该知道任何关于 UI 组件的信息,因此您可以使用
Application.Current.Dispatcher.Invoke( () => { ProgressBarValue = i; } );
这将更新您的进度条。
此外,查看更常见的 INotifyPropertyChanged 实现,例如来自 ReSharper 的实现,其中包含检查值是否真正更改的实现。
我只需将 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.
public void OnOk()
{
th = new Thread(new ThreadStart(StartProcess));
th.Start();
}
您可能还想在用户关闭表单时中止此线程。
此代码将取决于您的 MVVM 框架。这里我使用从 Caliburn.Micro 的 Screen
class 派生的视图模型,因此我可以重写 OnDeactivate
方法并在那里关闭线程。
protected override void OnDeactivate(bool close)
{
if (close)
{
th.Abort();
}
}