【发布时间】:2011-07-13 19:38:41
【问题描述】:
我正在尝试以小“块”或页面从数据库中读取大量行并将进度报告给用户;即,如果我正在加载 100 个“块”,则在加载每个块时报告进度。
我在 C# 4.0 中使用 TPL 从数据库中读取这些块,然后将完整的结果集交给另一个可以使用它的任务。我觉得与 BackgroundWorker 等相比,TPL 让我能够更好地控制任务取消和移交,但似乎没有内置的方式来报告任务的进度。
这是我为向 WPF 进度条报告进度而实施的解决方案,我想确保这是适当的,并且没有更好的方法我应该采用。
我首先创建了一个简单的界面来表示变化的进度:
public interface INotifyProgressChanged
{
int Maximum { get; set; }
int Progress { get; set; }
bool IsIndeterminate { get; set; }
}
这些属性可以绑定到 WPF 视图中的 ProgressBar,并且接口由负责启动数据加载并最终报告整体进度的支持 ViewModel 实现(在此示例中进行了简化):
public class ContactsViewModel : INotifyProgressChanged
{
private IContactRepository repository;
...
private void LoadContacts()
{
Task.Factory.StartNew(() => this.contactRepository.LoadWithProgress(this))
.ContinueWith(o => this.UseResult(o));
}
}
您会注意到我将 ViewModel 作为 INotifyProgressChanged 传递给存储库方法,这是我想确保我没有做错什么的地方。
我的想法是,为了报告进度,实际执行工作的方法(即存储库方法)需要访问 INotifyProgressChanged 接口,以便报告最终更新视图的进度。下面是对存储库方法的快速浏览(本示例的缩写):
public class ContactRepository : IContactRepository
{
...
public IEnumberable<Contact> LoadWithProgress(INotifyProgressChanged indicator)
{
var resultSet = new List<Contact>();
var query = ... // This is a LINQ to Entities query
// Set the maximum to the number of "pages" that will be iterated
indicator.Maximum = this.GetNumberOfPages(query.Count(), this.pageSize);
for (int i = 0; i < indicator.Maximum; i++)
{
resultSet.AddRange(query.Skip(i * this.pageSize).Take(this.pageSize));
indicator.Progress += 1; // As each "chunk" is loaded, progress is updated
}
// The complete list is returned after all "chunks" are loaded
return resultSet.AsReadOnly();
}
}
这就是存储库最终通过 ViewModel 向 View 报告进度的方式。这是正确的方法吗?我是否正确使用了 TPL,违反了任何主要规则等?此解决方案正在运行,正在按预期报告进度,我只是想确保我没有为失败做好准备。
【问题讨论】:
标签: c# c#-4.0 progress-bar task-parallel-library