假设我们有一个具有分层架构的应用程序。在视图中我们使用MVC或MVVM。该模型被视为域,它具有很好的业务逻辑。
现在让我们假设我们在模型中有一个需要一些时间的方法。例如,必须对对象的每个项目进行复杂的计算或处理。
在UI中,我们希望显示一个进度条和一个显示当前计算步骤的文本(例如包含所有过程历史记录的列表框)。
你会怎么做?如何从模型中发送进程进度信息以及如何连接Controller或ViewModel以便更新进度?
答案 0 :(得分:6)
我经常以下面的方式实现这一点。我的业务层流程需要很长时间才能运行,每隔一段时间就会引发事件,以表明它正在达到特定的“里程碑”。您可以决定通过事件发出信号的里程碑以及有多少里程碑。如果您的耗时过程是一个简单的循环,您可以选择,例如,循环中每10%的项目一次又一次地引发相同的事件。如果它是具有不同阶段的过程,您可以选择在每个阶段完成时引发不同的事件。
现在,您的表示层会订阅这些事件并执行相应的操作,更新进度条,文本或其他内容。
这种机制很好,因为:
希望这有帮助。
答案 1 :(得分:2)
我建议您查看BackgroundWorker
命名空间中提供的System.ComponentModel
类。
后台工作程序提供在单独的线程上运行密集型操作所需的方法,并接收有关其进度的状态更新(通过ReportProgress
,ProgressChanged
和RunWorkerCompleted
)。< / p>
实际上,我个人一直在尝试在Web环境中使用BackgroundWorker
,以便运行计划任务。我决定发布我迄今为止在codeplex上所做的工作。我觉得我的代码精神对你的情况很有用。 'Web Scheduled Task Framework' codeplex project
如果您选择下载项目,您将看到我如何使用BackgroundWorker
课程中的ScheduledTaskRunner
课程。我的实现没有将进度事件附加到工作者,但这样做很容易。此外,我当前的实现侧重于在给定间隔上运行任务,但将其修改为更多“按需”处理队列并不是非常困难。我甚至可以将其作为一个功能添加到现在我考虑它:)
假设你按照我上面的代码的方法,很容易在你的控制器上创建一个被触发的动作来检查“任务”列表(或你感兴趣的特定任务)并报告信息作为某种ActionResult
。设置一些javascript以在指定的时间间隔内轮询该操作,您将获得进度!
祝您好运,如果您对我的代码有任何疑问,请与我联系。
答案 2 :(得分:1)
我对以下类似的案例采取了以下方法。这个视图有一个动作,可能需要很长时间,我想定期显示进度。长时间运行的操作被推送到另一个类Worker。某些用户操作会在TestViewModel中启动对DoSomething
的调用。
TestView.xaml
...
<!-- Progress bar -->
<ProgressBar Visibility="Visible" Height="10" Value="{Binding SomeValue}"/>
...
TestViewModel.cs扩展了BaseViewModel,BaseViewModel只实现了INotifyPropertyChanged
...
private void DoSomething(){
Worker worker = new Worker();
worker.ProgressChanged += new EventHandler<WorkerEventArgs>(OnProgressChanged);
worker.Start();
}
private void OnProgressChanged(object sender, WorkerEventArgs args){
SomeValue = args.Progress;
}
private const String SomeValuePropertyName = "SomeValue";
private double someValue;
public double SomeValue
{
get
{
return someValue;
}
set
{
if (someValue == value)
{
return;
}
someValue = value;
NotifyPropertyChanged(SomeValuePropertyName);
}
}
...
Worker.cs
...
public event EventHandler<WorkerEventArgs> ProgressChanged;
public void Start(){
//This will take a long time. Periodically call NotifyProgress
}
private void NotifyProgress()
{
if (ProgressChanged != null)
{
double progress = ...; //calculate progress
ProgressChanged(this, new WorkerEventArgs(progress));
}
}
...
WorkerEventArgs.cs
public class WorkerEventArgs : EventArgs
{
public double Progress { get; private set; }
public WorkerEventArgs(double progress)
{
Progress = progress;
}
}
答案 3 :(得分:1)
根据您的其他评论,您尝试尽可能保持业务层的清洁。
然后,模型视图ViewModel方法可能适合:http://en.wikipedia.org/wiki/Model_View_ViewModel
计算完成后,您将抛出已取得进展的事件。
这些事件在ViewModel中捕获,并且更新了进度。
由于ViewModel和View(观察者模式)之间的数据绑定,视图随后被更新
答案 4 :(得分:0)
您需要探索观察者模式(http://en.wikipedia.org/wiki/Observer_pattern)。这是桌面应用程序的常用方法。它对Web来说有点复杂。您可能还想查看Comet [http://en.wikipedia.org/wiki/Comet_(programming)],看看它是如何为网络完成的。