好的,我已经在这个问题上花费了几天时间,我认为我掌握了它。
首先,这里有一个非常重要的部分。为了使分页正常工作,分页器必须知道总项数,无论当前查询返回了多少项。如果查询返回所有内容,则项目计数显然是返回的项目数量。对于智能分页,项目计数仍然是可用项目的总数,尽管查询只返回显示的内容。通过过滤,即使可用项目的总数随着筛选器更改而更改。
Silverlight Datapager控件具有名为ItemCount的属性。它是只读的,并且不能在XAML中进行数据绑定,也不能直接在代码中设置。但是,如果包含分页器的用户控件具有实现IPagedCollectionView的DataContext,则数据上下文对象必须实现带有PropertyChanged通知的ItemCount属性,并且DataPager似乎会自动获取此属性。
其次,我强烈推荐Brad Abrams出色的RIA Services博客系列文章,特别是关于ViewModel的文章。它包含了大部分你需要让分页和过滤工作的内容,尽管缺少管理项目计数的关键部分。他的可下载示例还包含一个非常好的基本框架,用于实现ModelViewViewModel(MVVM)。谢谢你,Brad!
所以这里是如何使项目计数起作用的方法。(这段代码引用了一个自定义ORM,而Brad的代码使用Entity Framework;通过两者,您可以在您的环境中找到需要的东西。)
首先,您的ORM需要支持获取记录计数,带有或不带筛选器。这是我的领域服务代码,使计数可用于RIA Services:
[Invoke]
public int GetExamCount()
{
return Context.Exams.Count();
}
[Invoke]
public int GetFilteredExamCount(string descriptionFilter)
{
return Context.Exams.GetFilteredCount(descriptionFilter);
}
注意[Invoke]属性。对于任何不返回实体或实体集合的DomainService方法,都需要使用此属性。
现在是ViewModel代码。当然你需要一个ItemCount。(这来自Brad的示例。)
int itemCount;
public int ItemCount
{
get { return itemCount; }
set
{
if (itemCount != value)
{
itemCount = value;
RaisePropertyChanged(ItemCountChangedEventArgs);
}
}
}
您的LoadData方法将运行查询以获取当前用于在DataGrid中显示的行集。 (这还没有实现自定义排序,但这很容易添加。)
EntityQuery<ExamEntity> query =
DomainContext.GetPagedExamsQuery(PageSize * PageIndex, PageSize, DescriptionFilterText);
DomainContext.Load(query, OnExamsLoaded, null);
回调函数会运行查询以获取计数。如果没有使用筛选器,则获取所有行的计数;如果使用了筛选器,则获取经过筛选的行的计数。
private void OnExamsLoaded(LoadOperation<ExamEntity> loadOperation)
{
if (loadOperation.Error != null)
{
ErrorRaising(this, new ErrorEventArgs(loadOperation.Error));
}
else
{
Exams.MoveCurrentToFirst();
if (string.IsNullOrEmpty(DescriptionFilterText))
{
DomainContext.GetExamCount(OnCountCompleted, null);
}
else
{
DomainContext.GetFilteredExamCount(DescriptionFilterText, OnCountCompleted, null);
}
IsLoading = false;
}
}
还有一个用于计数的回调方法:
void OnCountCompleted(InvokeOperation<int> op)
{
ItemCount = op.Value;
TotalItemCount = op.Value;
}
通过设置ItemCount,Datapager控件可以获取它,并且我们可以使用分页和过滤功能的智能查询,只返回要显示的记录!
LINQ使用.Skip()和.Take()使查询变得容易。使用原始的ADO.NET更难。我学会了如何拆解由LINQ生成的查询来完成这个任务。
SELECT * FROM
(select ROW_NUMBER() OVER (ORDER BY Description) as rownum, *
FROM Exams as T0 WHERE T0.Description LIKE @description ) as T1
WHERE T1.rownum between @first AND @last ORDER BY rownum
“select ROW_NUMBER() OVER (ORDER BY Description) as rownum”这个子句很有意思,因为还没有多少人使用“OVER”。该子句在给行编号之前按Description对表进行排序,并且筛选器也在分配行号之前应用。这使得外部SELECT可以在排序和筛选后过滤行号。
所以,在RIA服务和Silverlight中实现了智能分页和筛选!