REMIX09 Tokyo、B-2セッションデモ・解説(3)
ページング、ソーティング、フィルタリング、オートコンプリートボックス
前回のクエリでは、すべてのエントリが返されましたが、Webアプリケーションの世界では、ページングやサーバーサイドのソーティング、そしてフィルタリングなどを行いたいと考えるのが、当たり前ですよね?.NET RIA Servicesと、Silverlight 3から登場した新しいコントロールを組み合わせると、簡単にそれを行うことができるのです。どのようにしたら可能か見ていきましょう。
最初に、前回追加したコードビハインドをすべて削除します。
<Home.xaml.cs >
public Home()
{
InitializeComponent();
}
そして、それらに代わって、Home.xamlの中に、DomainDataSourceというものを追加しましょう。詳しくは.NET RIA ServicesのPreviewの文書を読んで戴ければと思いますが、REMIXのセッションでもご説明した通り、SilverlightのXAMLのコントロールで、DomainServiceにマッピングできるものだと考えておいて戴ければOKです。これも、Toolboxからドラッグ&ドロップできます。そして、下記のように編集してみてください。
<Home.xaml (TextBlockの後)>
<riaControls:DomainDataSource x:Name="dds"
AutoLoad="True"
QueryName="GetSuperEmployeesQuery"
LoadSize="20">
<riaControls:DomainDataSource.DomainContext>
<App:SuperEmployeeDomainContext/>
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
3行目では、GetSuperEmployeesQuery メソッドをDomainContextから取得しています。これは6行目に特定されています。 4行目で注目すべきは、LoadSize を20に設定しているところです。これは、ダウンロードするデータを一度に20件にしたいということです。.NET RIA Servicesのように非同期処理でありながら同期処理に近いソリューションを作成するときは、パフォーマンス上も極めて重要な制御になってきます。
それでは、これを当該DataGridにバインドし、アクティビティコントロールを使って、プログレスインジケータつきにして見ましょう。
<Home.xaml >
<activity:Activity IsActive="{Binding IsBusy, ElementName=dds}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="900" Margin="10,5,10,0">
<StackPanel>
<data:DataGrid x:Name="dataGrid1" Height="300" Width="900"
ItemsSource="{Binding Data, ElementName=dds}">
</data:DataGrid>
<data:DataPager PageSize="10" Width="900"
HorizontalAlignment="Left"
Source="{Binding Data, ElementName=dds}"
Margin="0,0.2,0,0" />
</StackPanel>
</activity:Activity>
6行目に、データグリッドがあります。これは当該dds.Data プロパティにバインドされています (7行目)。そして、9行目で、DataPager を追加しています。これは、同じデータソースにバインドされています。これにより、Paging UIが実現できます。注意すべきは9行目、表示するレコードを一度に10件にしています。最終的に、すべての内容を一つのActivityControlに入れて、進行状況を表示します。
ActivityControl、DataGrid、そしてDataPagerの素晴らしい点は、どれも多くのデータ、たとえばWCFサービスから取得したデータ、RESTサービスから取得したデータ、と一緒に使えるという点です。それでは、 F5を押して実行してみましょう。
注目すべきは、20件のレコードを一度にロードしていますが、表示しているのは10件だけという点です。すなわち、1ページ進むのはクライアント側だけの処理ですが、さらに1ページ進もうとすると、サーバー側に問い合わせてデータを取得し次の20件をロードするわけです。これはソーティングでもすべて同様に動きます。 もう一つ素晴らしい点は、これらすべての処理を行うのに、サーバー側・クライアント側のいずれにもコードを追加していません。これは、まさにLINQのもたらすマジックです。
・グルーピング
次に、グルーピングを追加します。出版社でグルーピングするようにPublishersを設定します。
<Home.xaml >
<riaControls:DomainDataSource.GroupDescriptors>
<datagroup:GroupDescriptor PropertyPath="Publishers" />
</riaControls:DomainDataSource.GroupDescriptors>
・フィルタリング
それでは、フィルタリングも追加してみましょう。最初に、ラベルとテキストボックスを追加します。
<Home.xaml >
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Origin: "></TextBlock>
<TextBox x:Name="originFilterBox" Width="75" Height="20"></TextBox>
</StackPanel>
そして次に、これらのフィルターボックスをDomainDataSourceに追加します。
<Home.xaml >
<riaControls:DomainDataSource.FilterDescriptors>
<datagroup:FilterDescriptorCollection>
<datagroup:FilterDescriptor PropertyPath="Origin"
Operator="StartsWith">
<datagroup:ControlParameter PropertyName="Text"
RefreshEventName="TextChanged"
ControlName="originFilterBox">
</datagroup:ControlParameter>
</datagroup:FilterDescriptor>
</datagroup:FilterDescriptorCollection>
</riaControls:DomainDataSource.FilterDescriptors>
F5を押して実行すると、フィルターボックスが追加されています。そして、何かをその中にタイプすると、サーバー側で結果のフィルタリングが行われます。 ここでは“Animal”と打ってみました。
・オートコンプリートボックスによるフィルタリング
さて、このような場合には、シンプルなテキストボックスよりは、オートコンプリートボックスが欲しくなります。追加しましょう。ここで最初にやらなければならないのは、すべてのオプションを取得することです。注意すべきは、それらのオプションは、すべてサーバー側から取得する必要があることです (クライアントは、すべてのオプションを知らないかもしれません。ページング等を行っているためです)。これを行うためには、サーバー側のDomainServiceにメソッドを追加します。
<SuperEmployeeDomainService.cs >
public class Origin
{
public Origin() { }
[Key]
public string Name { get; set; }
public int Count { get; set; }
}
そして、このメソッドはOriginsを取得して返します。
<SuperEmployeeDomainService.cs >
public IQueryable<Origin> GetOrigins()
{
var q = (from emp in Context.SuperEmployeeSet
select emp.Origin).Distinct()
.Select(name => new Origin
{
Name = name,
Count = Context.SuperEmployeeSet.Count
(emp => emp.Origin.Trim() == name.Trim())
});
q = q.Where(emp => emp.Name != null);
return q;
}
そして、Silverlight 3 SDKにある、オートコンプリートコントロールを追加する必要があります。先程追加したテキストボックスを削除して下記のように入力します。
<Home.xaml >
<input:AutoCompleteBox
x:Name="originFilterBox"
Width="75" Height="30"
ValueMemberBinding="{Binding Name}"
ItemTemplate="{StaticResource OriginsDataTemplate}" >
</input:AutoCompleteBox>
さらに、これをロードするために、コードビハインドに若干の追加が必要になります。
<Home.xaml.cs >
public Home()
{
InitializeComponent();
var context = dds.DomainContext as SuperEmployeeDomainContext;
originFilterBox.ItemsSource = context.Origins;
context.Load(context.GetOriginsQuery());
}
F5を押して実行すると、結果は下記の通りです。
ここまでいかがでしょうか?かなりいろいろなことができることがおわかりいただけたかと思います。次は、Mater / DetailへのXAMLの変更とバリデーションの追加を説明します。