Хорошо, я провел несколько дней в сорняках с этим, и я думаю, что у меня есть справка.
Во-первых, важная часть магии. Для правильной работы пейджинга пейджер должен знать общее количество элементов независимо от того, сколько элементов было возвращено текущим запросом. Если запрос возвращает все, количество элементов, очевидно, равно количеству возвращенных элементов. Для интеллектуальной подкачки количество элементов по-прежнему равно сумме доступных элементов, хотя запрос возвращает только то, что отображается. При фильтрации даже общее количество доступных элементов изменяется каждый раз, когда меняется фильтр.
Элемент управления Silverlight Datapager имеет свойство ItemCount. Он доступен только для чтения и не может быть привязан к данным в XAML или установлен непосредственно в коде. Однако если пользовательский элемент управления, содержащий пейджер, имеет DataContext, который реализует IPagedCollectionView, то объект контекста данных должен реализовать свойство ItemCount с уведомлением PropertyChanged, и DataPager, похоже, подхватывает это автоматически.
Во-вторых, я настоятельно рекомендую серию великолепных сообщений Брэда Абрамса в RIA Services , особенно эту статью о ViewModel . Он содержит большую часть того, что вам нужно, чтобы пейджинг и фильтрация работали, хотя в нем отсутствует важная часть управления количеством элементов. Его загружаемый образец также содержит очень хорошую базовую среду для реализации ModelViewViewModel (MVVM). Спасибо, Брэд!
Итак, вот как заставить работать счетчик предметов. (Этот код относится к пользовательскому ORM, в то время как код Брэда использует 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, конечно. (Это из примера Брэда.)
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 Services и Silverlight!