好的,我已经用这个在杂草中度过了几天,我想我已经掌握了它。
首先,一个重要的魔法。为了使分页正常工作,分页器必须知道总项目数,无论当前查询返回了多少项目。如果查询返回所有内容,则项目计数显然是返回的项目数。对于智能分页,项目计数仍然是可用项目的总数,尽管查询只返回显示的内容。使用过滤器,每次过滤器更改时,甚至可用项目的总数都会更改。
Silverlight Datapager 控件有一个名为 ItemCount 的属性。它是只读的,不能在 XAML 中进行数据绑定,也不能直接在代码中设置。但是,如果包含寻呼机的用户控件具有实现 IPagedCollectionView 的 DataContext,则数据上下文对象必须实现带有 PropertyChanged 通知的 ItemCount 属性,并且 DataPager 似乎会自动拾取这一点。
其次,我强烈推荐 Brad Abrams关于 RIA Services 的一系列优秀博文,尤其是关于ViewModel的这篇博文。它包含了进行分页和过滤工作所需的大部分内容,尽管它缺少管理项目计数的关键部分。他的可下载示例还包含一个非常好的实现 ModelViewViewModel (MVVM) 的基本框架。谢谢你,布拉德!
所以这里是如何使项目计数工作。(此代码指的是自定义 ORM,而 Brad 的代码使用实体框架;在两者之间,您可以确定您在环境中需要什么。)
首先,您的 ORM 需要支持获取记录计数,无论是否使用过滤器。这是我的域服务代码,它使 RIA 服务可以使用计数:
[Invoke]
public int GetExamCount()
{
return Context.Exams.Count();
}
[Invoke]
public int GetFilteredExamCount(string descriptionFilter)
{
return Context.Exams.GetFilteredCount(descriptionFilter);
}
注意 [Invoke] 属性。对于不返回 Entity 或 Entity 集合的任何 DomainService 方法,您都需要它。
现在查看 ViewModel 代码。当然,您需要一个 ItemCount。(这是来自布拉德的例子。)
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)
{
//raise an event...
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”。此子句在分配行号之前按说明对表进行排序,并且在分配行号之前也应用过滤器。这允许外部 SELECT 在排序和过滤之后过滤行号。
就是这样,在 RIA 服务和 Silverlight 中使用过滤的智能分页!