Silverlight、DataPager、RIA Services和智能分页

13

我仍在努力适应Silverlight和RIA Services,当然会从一些更“有趣”的事情入手,比如网格和智能分页。我可以连接到RIA Services(使用自己开发的ORM,而不是L2S或EF),在网格上获取数据,并连接到DataPager。至少对于查询来说,域服务与自己开发的ORM很好地配合工作。(仍在致力于完整的CRUD操作。)但是,还存在问题:

  1. 为了支持用户应用程序,我需要用户控制的排序和过滤功能,除了智能分页(只运行需要显示的行的查询)和分组。

  2. 到目前为止,在DataGrid或DataPager中没有看到任何外部化这些功能的东西,以便将过滤、排序和分页参数传递到服务器,以构建适当的查询。

  3. 数据集可能相当大;我选择用于原型制作的表在某些客户端可以有多达35,000个条目,我相信还有其他表要大得多,我将不得不处理。因此,“智能分页”方面至关重要。

欢迎提出想法、建议、指导和nerf砖。

3个回答

11

好的,我已经在这个问题上花费了几天时间,我认为我掌握了它。

首先,这里有一个非常重要的部分。为了使分页正常工作,分页器必须知道总项数,无论当前查询返回了多少项。如果查询返回所有内容,则项目计数显然是返回的项目数量。对于智能分页,项目计数仍然是可用项目的总数,尽管查询只返回显示的内容。通过过滤,即使可用项目的总数随着筛选器更改而更改。

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)
    {
        //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”。该子句在给行编号之前按Description对表进行排序,并且筛选器也在分配行号之前应用。这使得外部SELECT可以在排序和筛选后过滤行号。

所以,在RIA服务和Silverlight中实现了智能分页和筛选!


3
当我遇到像这样的框架问题时,这些框架本应使常见任务更加容易,例如分页。这让人有点担心。是使用 RIA 还是不使用 RIA,这是个问题… - sipsorcery
那是一个开放性的问题。Silverlight 3和VS 2008的RIA服务已经基本上死亡了;现在可用的是公共测试版,不会得到增强,并且仅支持到12月。因此,RIA Services for Silverlight 4和VS 2010是一个选择。它现在处于RC2状态;一旦发布,我会立即检查它。顺便说一句,Brad Abrams建议让Silverlight datagrid进行分页,但仍然存在自定义过滤的问题,这正是最初让我放弃RIA服务的原因。我们必须能够在服务器上进行筛选。 - Cylon Cat

4

以下是简单而快速的解决方案(我采用的方法):

只需将您的DomainDataSource移动到ViewModel中!完成!

可能不太适合可测试性,可能还有其他限制,我还没有发现,但个人认为在更好的东西出现之前,我不关心这些。

在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中提取出来!


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接