我仍然试图通过Silverlight和RIA Services站稳脚跟,当然还要从一些更“有趣”的东西开始,比如网格和智能分页。我可以连接到RIA Services(使用自行开发的ORM,而不是L2S或EF),在网格上获取数据,并连接到DataPager。域服务与本土ORM一起运行良好,至少对于查询而言。 (仍在使用完整的CRUD。)但是,仍有问题:
为了支持用户应用程序,我需要用户控制的排序和过滤,以及智能分页(仅运行查询显示所需的行)和分组。
到目前为止,我在DataGrid或DataPager中都没有看到外部化这些功能,因此可以将过滤,排序和分页参数传递给服务器以构建适当的查询。
数据集可能非常大;我选择用于原型制作工作的我的表可以在一些客户中拥有多达35,000个条目,我确信还有其他更大的表格,我将不得不在某个时候处理。因此,“智能寻呼”方面至关重要。
欢迎提出想法,建议,指导和nerf砖。
答案 0 :(得分:11)
好的,我已经花了几天杂草用这个,我想我已经掌握了它。
首先,一件重要的魔法。要使分页正常工作,无论当前查询返回多少项,寻呼机都必须知道总项数。如果查询返回所有内容,则项目计数显然是返回的项目数。对于智能分页,项目计数仍然是可用项目的总数,尽管查询仅返回显示的内容。通过过滤,每次过滤器更改时,即使可用项目总数也会发生变化。
Silverlight Datapager控件有一个名为ItemCount的属性。它是只读的,不能在XAML中数据绑定,或直接在代码中设置。但是,如果包含寻呼机的用户控件具有实现IPagedCollectionView的DataContext,则数据上下文对象必须使用PropertyChanged通知实现ItemCount属性,并且DataPager似乎自动选择它。
其次,我强烈推荐布拉德艾布拉姆斯出色的series of blog posts on 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
条款“选择ROW_NUMBER()OVER(ORDER BY Description)作为rownum”是有趣的部分,因为还没有很多人使用“OVER”。此子句在分配行号之前对“描述”上的表进行排序,并且在分配行号之前也应用过滤器。这允许外部SELECT在排序和过滤后对行号进行过滤。
因此,在RIA Services和Silverlight中进行智能分页和过滤!
答案 1 :(得分:4)
这是快速而肮脏的解决方案(我去过):
将您的DomainDataSource
移至ViewModel!完成!
对于可测试性可能并不是很好,可能还有其他一些我尚未发现的限制,但我个人并不关心直到 something better comes along。
在ViewModel中只是实例化数据源:
// Feedback DataSource
_dsFeedback = new DomainDataSource();
_dsFeedback.DomainContext = _razorSiteDomainContext;
_dsFeedback.QueryName = "GetOrderedFeedbacks";
_dsFeedback.PageSize = 10;
_dsFeedback.Load();
并提供可绑定属性:
private DomainDataSource _dsFeedback { get; set; }
public DomainDataSource Feedback
{
get
{
return _dsFeedback;
}
}
将您的DataPager添加到您的XAML:
<data:DataPager Grid.Row="1"
HorizontalAlignment="Stretch"
Source="{Binding Feedback.Data}"
Margin="0,0,0,5" />
<data:DataGrid ItemsSource="{Binding Feedback.Data}">
PS。感谢上面链接页面中的'Francois'。在我看到你的评论之前,我甚至没有意识到我可以将DomainDataSource从XAML中取出来!
答案 2 :(得分:0)
这是一篇有趣的文章,从2010年5月开始,关于框架中此类功能可能的未来支持。
http://www.riaservicesblog.net/Blog/post/WCF-RIA-Services-Speculation-EntityCollectionView.aspx