Silverlight, DataPager, usługi RIA i smart paging

Nadal staram się stanąć na nogi z Silverlight i RIA Services, i oczywiście zaczynając od niektórych bardziej "zabawnych" rzeczy, takich jak siatki i inteligentne stronicowanie. Mogę połączyć się z usługami RIA (używając domowego ORM, a nie L2S lub EF), pobrać dane z sieci i połączyć się z Datapagerem. Usługa domeny działa dobrze z domowym ORM, przynajmniej dla zapytań. (Nadal pracuje nad pełnym CRUD.) Jednak nadal są problemy:

  1. Aby wesprzeć użytkownika aplikacja, potrzebuję kontrolowanego przez użytkownika sortowania i filtrowania, oprócz inteligentnego stronicowania (uruchom tylko Zapytanie o wiersze potrzebne do wyświetlenia) i grupowania.

  2. Do tej pory nie widziałem w DataGrid lub DataPager nic, aby uzewnętrznić te możliwości, tak aby filtrowanie, sortowanie i stronicowanie parametrów mogły być przekazywane do serwera w celu zbudowania odpowiedniego zapytania.

  3. Zbiory danych są potencjalnie dość duże; mój stół, który wybrałem do prac prototypowych, może mieć do 35 000 wpisy u niektórych klientów, i jestem pewien, że są inne tabele znacznie większe, że będę musiał poradzić sobie w pewnym momencie. Tak więc aspekt" inteligentnego stronicowania " jest niezbędny.

Pomysły, sugestie, wskazówki i klocki nerf są mile widziane.

Author: Cylon Cat, 2010-02-18

3 answers

Ok, spędziłem kilka dni w chwastach z tym i myślę, że sobie z tym poradzę.

Po pierwsze, ważny kawałek magii. Aby stronicowanie działało poprawnie, pager musi znać całkowitą liczbę pozycji, bez względu na to, ile pozycji zostało zwróconych przez bieżące zapytanie. Jeśli zapytanie zwróci wszystko, liczba pozycji jest oczywiście liczbą zwróconych pozycji. W przypadku Inteligentnego stronicowania liczba pozycji jest nadal sumą dostępnych pozycji, chociaż zapytanie zwraca tylko to, co zostanie wyświetlone. Dzięki filtrowaniu nawet suma dostępnych elementów zmienia się za każdym razem, gdy zmienia się filtr.

Kontrola Silverlight Datapager posiada właściwość ItemCount. Jest tylko odczytywany i nie może być zapisywany w XAML, ani ustawiany bezpośrednio w kodzie. Jeśli jednak kontrola użytkownika zawierająca pager ma DataContext implementujący IPagedCollectionView, to obiekt kontekstu danych musi zaimplementować właściwość ItemCount z powiadomieniem PropertyChanged, a DataPager zdaje się to odbierać automagicznie.

Po Drugie, Gorąco polecam znakomitą serię blogów Brada Abramsa na temat usług RIA , szczególnie ten na ViewModel . Zawiera większość tego, czego potrzebujesz, aby stronicowanie i filtrowanie działały, chociaż brakuje w nim krytycznego elementu zarządzania liczbą elementów. Jego próbka do pobrania zawiera również bardzo dobry podstawowy framework do implementacji ModelViewViewModel (MVVM). Dziękuję, Brad!

Oto jak sprawić, by licznik przedmiotów działał. (To kod odnosi się do niestandardowego ORM, podczas gdy kod Brada wykorzystuje Framework encji; pomiędzy tymi dwoma możesz określić, czego potrzebujesz w swoim środowisku.)

Po pierwsze, twój ORM musi wspierać uzyskiwanie rekordów, z filtrem i bez niego. Oto Mój kod serwisowy domeny, który umożliwia liczenie usług RIA:

[Invoke]
public int GetExamCount()
{
    return Context.Exams.Count();
}

[Invoke]
public int GetFilteredExamCount(string descriptionFilter)
{
    return Context.Exams.GetFilteredCount(descriptionFilter);
}

Zwróć uwagę na atrybut [Invoke]. Jest to potrzebne dla każdej metody DomainService, która nie zwraca encji ani kolekcji encji.

Teraz dla ViewModel kod. Oczywiście potrzebujesz ItemCount. (To z przykładu Brada.)

    int itemCount;
    public int ItemCount
    {
        get { return itemCount; }
        set
        {
            if (itemCount != value)
            {
                itemCount = value;
                RaisePropertyChanged(ItemCountChangedEventArgs);
            }
        }
    }

Twoja metoda LoadData uruchomi zapytanie, aby pobrać bieżący zestaw wierszy do wyświetlenia w DataGrid. (To nie implementuje jeszcze niestandardowego sortowania, ale jest to łatwe dodanie.)

    EntityQuery<ExamEntity> query = 
        DomainContext.GetPagedExamsQuery(PageSize * PageIndex, PageSize, DescriptionFilterText);
    DomainContext.Load(query, OnExamsLoaded, null);

Metoda wywołania zwrotnego następnie uruchamia zapytanie, aby uzyskać zliczenia. Jeśli nie jest używany filtr, otrzymujemy liczbę dla wszystkich wierszy; jeśli jest filtr, wtedy otrzymujemy liczbę dla przefiltrowanych wierszy.

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;
    }
}

Jest też metoda wywołania zwrotnego dla zliczania:

void OnCountCompleted(InvokeOperation<int> op)
{
    ItemCount = op.Value;
    TotalItemCount = op.Value;
}

Z zestawem ItemCount, Kontrola Datapager odbiera go, a my mamy stronicowanie z filtrowaniem i inteligentne zapytanie, które zwraca tylko rekordy do wyświetlenia!

LINQ ułatwia zapytanie .Skip () i .Take (). Robienie tego z raw ADO.NET jest trudniejsze. Nauczyłem się, jak to zrobić, rozkładając na części zapytanie generowane przez 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

Klauzula "select ROW_NUMBER () OVER (ORDER BY Description) as rownum" jest interesującą częścią, ponieważ nie Wiele osób używa jeszcze "OVER". Ta klauzula sortuje tabelę w opisie przed przypisaniem numerów wierszy, a filtr jest również stosowany przed przypisaniem numerów wierszy. Dzięki temu zewnętrzny SELECT może filtrować po numerach wierszy, po sortowaniu i filtrowaniu.

Więc jest, inteligentne stronicowanie z filtrowaniem, w usługach RIA i Silverlight!

 11
Author: Cylon Cat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-19 14:25:07

Oto szybkie i brudne rozwiązanie (które wybrałem):

Po prostu przenieś swój DomainDataSource do swojego ViewModel! Zrobione!

Może nie do końca nadaje się do testowania i prawdopodobnie innych ograniczeń, których jeszcze nie odkryłem, ale osobiście nie dbam o to , dopóki pojawia się coś lepszego .

Wewnątrz ViewModel wystarczy utworzyć instancję źródła danych:

// Feedback DataSource
_dsFeedback = new DomainDataSource();
_dsFeedback.DomainContext = _razorSiteDomainContext;
_dsFeedback.QueryName = "GetOrderedFeedbacks";
_dsFeedback.PageSize = 10;
_dsFeedback.Load();

I dostarczyć właściwość bindowalną:

private DomainDataSource _dsFeedback { get; set; }
public DomainDataSource Feedback 
{
    get 
    {
        return _dsFeedback;
    }
}

I dodaj swój DataPager do twojego XAML:

  <data:DataPager Grid.Row="1"
                  HorizontalAlignment="Stretch" 
                  Source="{Binding Feedback.Data}" 
                  Margin="0,0,0,5" />

  <data:DataGrid ItemsSource="{Binding Feedback.Data}">


PS. Podziękowania dla 'Francois' z wyżej podlinkowanej strony. Nawet nie zdawałem sobie sprawy, że mogę wyjąć DomainDataSource z XAML, dopóki nie zobaczyłem Twojego komentarza!

 4
Author: Simon_Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-14 03:38:35

Jest to ciekawy artykuł z maja 2010 roku o ewentualnym przyszłym wsparciu dla tego typu funkcji w ramach.

Http://www.riaservicesblog.net/Blog/post/WCF-RIA-Services-Speculation-EntityCollectionView.aspx

 0
Author: Simon_Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-14 03:25:01