13

私はまだSilverlightとRIAサービスを使って足を踏み入れようとしています。もちろん、グリッドやインテリジェントページングなどのより「楽しい」ものから始めています。RIAサービスに接続し(L2SやEFではなく自家製のORMを使用)、グリッドでデータを取得し、DataPagerに接続できます。ドメインサービスは、少なくともクエリに関しては、自家製のORMでうまく機能しています。(まだ完全なCRUDに取り組んでいます。)ただし、まだ問題があります。

  1. ユーザーアプリケーションをサポートするには、スマートページング(表示に必要な行に対してのみクエリを実行する)とグループ化に加えて、ユーザーが制御する並べ替えとフィルタリングが必要です。

  2. これまでのところ、DataGridまたはDataPagerでこれらの機能を外部化して、フィルタリング、並べ替え、およびページングのパラメーターをサーバーに渡して適切なクエリを作成できるようにするものは何もありません。

  3. データセットは潜在的に非常に大きいです。私がプロトタイピング作業用に選択したテーブルには、一部の顧客で最大35,000のエントリを含めることができます。また、ある時点で処理しなければならないはるかに大きなテーブルが他にもあると確信しています。したがって、「スマートページング」の側面が不可欠です。

アイデア、提案、ガイダンス、およびナーフブリックはすべて大歓迎です。

4

3 に答える 3

11

さて、私はこれと一緒に雑草で数日過ごしました、そして私はそれを理解していると思います。

まず、重要な魔法です。ページングが正しく機能するためには、現在のクエリによって返されたアイテムの数に関係なく、ページャーはアイテムの総数を知っている必要があります。クエリがすべてを返す場合、アイテム数は明らかに返されたアイテムの数です。スマートページングの場合、クエリは表示されたものだけを返しますが、アイテム数は引き続き使用可能なアイテムの合計です。フィルタリングを使用すると、フィルターが変更されるたびに、使用可能なアイテムの合計も変更されます。

Silverlight Datapagerコントロールには、ItemCountというプロパティがあります。読み取り専用であり、XAMLでデータバインドしたり、コードで直接設定したりすることはできません。ただし、ページャーを含むユーザーコントロールにIPagedCollectionViewを実装するDataContextがある場合、データコンテキストオブジェクトはPropertyChanged通知を使​​用してItemCountプロパティを実装する必要があり、DataPagerはこれを自動的に取得するようです。

次に、RIAサービスに関するBrad Abramsの優れた一連のブログ投稿、特にViewModelに関するこのブログ投稿を強くお勧めします。アイテム数の管理に関する重要な部分が欠落していますが、ページングとフィルタリングを機能させるために必要なもののほとんどが含まれています。彼のダウンロード可能なサンプルには、ModelViewViewModel(MVVM)を実装するための非常に優れた基本的なフレームワークも含まれています。ありがとう、ブラッド!

アイテムカウントを機能させる方法は次のとおりです。(このコードはカスタムORMを参照していますが、BradのコードはEntity Frameworkを使用しています。2つの間で、環境に必要なものを把握できます。)

まず、ORMは、フィルターの有無にかかわらず、レコード数の取得をサポートする必要があります。カウントをRIAサービスで利用できるようにする私のドメインサービスコードは次のとおりです。

[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);

The callback method then runs the query to get the counts. If no filter is being used, we get the count for all rows; if there's a filter, then we get the count for filtered rows.

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

There's also a callback method for counts:

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

With the ItemCount set, the Datapager control picks it up, and we have paging with filtering and a smart query that returns only the records to be displayed!

LINQ makes the query easy with .Skip() and .Take(). Doing this with raw ADO.NET is harder. I learned how to do this by taking apart a LINQ-generated query.

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

The clause "select ROW_NUMBER() OVER (ORDER BY Description) as rownum" is the interesting part, because not many people use "OVER" yet. This clause sorts the table on Description before assigning row numbers, and the filter is also applied before row numbers are assigned. This allows the outer SELECT to filter on row numbers, after sorting and filtering.

So there it is, smart paging with filtering, in RIA Services and Silverlight!

于 2010-02-21T16:09:55.773 に答える
4

Here's the quick and dirty solution (that I went for):

Just move your DomainDataSource to your ViewModel! Done!

May not exactly be great for testability and probably some other limitations I haven't discovered yet, but personally I don't care about that until something better comes along.

Inside your ViewModel just instantiate the data source :

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

and provide a bindable property :

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

And add your DataPager to your XAML:

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

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


PS. Thanks to 'Francois' from the above linked page. I didn't even realize I could take the DomainDataSource out of the XAML until I saw your comment!

于 2010-08-14T03:38:35.557 に答える
0

This is an interesting article from May 2010 about the possible future support for this type of feature in the framework.

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

于 2010-08-14T03:25:01.497 に答える