かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

WCF RIA Services Toolkit December 2010試してみた

インストールは、Yesマンになれば出来たので割愛。早速データを取得するところまで試してみました。

DomainServiceの作成

ここらへんは変わらずです。さくっと作ってしまいましょう。
要注意なのが、Countメソッドを実装してやらないとページングとかが有効に出来ないみたいです。

namespace SilverlightApplication1.Web
{
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;


    [EnableClientAccess()]
    public class PeopleDomainService : DomainService
    {
        public IQueryable<Person> GetPeople()
        {
            return Enumerable.Range(1, 100).Select(i =>
                new Person { ID = i, Name = "太郎 " + i }).AsQueryable();
        }

        // ページングのために必要
        protected override int Count<T>(IQueryable<T> query)
        {
            return query.Count();
        }
    }

    public class Person
    {
        [Key]
        public int ID { get; set; }

        public string Name { get; set; }
    }
}

参照の追加

Silverlightのクライアント側にToolkitのアセンブリの参照を追加します。追加するのは、以下の2つです(1つはToolkitのじゃないけど)

  • Microsoft.Windows.Data.DomainServices
  • System.Windows.Data

ViewModelの作成

そして、ViewModelを作っていきます。ここでToolkitで追加されたViewModelにとってフレンドリーなように設計されたクラスを使います。

namespace SilverlightApplication1
{
    using System.ServiceModel.DomainServices.Client;
    using System.Windows;
    using Microsoft.Windows.Data.DomainServices;
    using SilverlightApplication1.Web;
    using System.ComponentModel;

    public class MainPageViewModel
    {
        // DomainContextのモック機能とか標準で追加されて欲しかったなぁ
        private PeopleDomainContext context = new PeopleDomainContext();

        // こいつはToolkitで追加されたObservableCollection<T>を実装した便利クラス
        public EntityList<Person> People { get; private set; }

        // こいつもToolkitで追加された便利クラス
        public DomainCollectionView<Person> PeopleView { get; private set; }

        public MainPageViewModel()
        {
            // EntityListを作るときにEntitySetを渡してやる必要がある
            this.People = new EntityList<Person>(this.context.Persons);
            // DomainCollectionViewを作るときにはDomainCollectionViewLoaderと
            // EntityListを渡してやる必要がある
            this.PeopleView = new DomainCollectionView<Person>(
                // 読み込み処理と読み込み完了処理のデリゲートを渡してやるs
                new DomainCollectionViewLoader<Person>(
                    this.LoadPeople,
                    this.LoadPeopleCompleted),
                this.People);

            // デザインモードのときは何もしない
            if (DesignerProperties.IsInDesignTool)
            {
                return;
            }

            using (this.PeopleView.DeferRefresh())
            {
                this.PeopleView.MoveToFirstPage();
                this.PeopleView.PageSize = 10;
            }
        }

        // 読み込み時のコールバック
        private LoadOperation<Person> LoadPeople()
        {
            // 普通にLoadする+ページングのためにSortPageAndCountをやる
            // ここでもDomainCollectionView渡さないといけない
            return this.context.Load(
                this.context.GetPeopleQuery().SortPageAndCount(this.PeopleView));
        }

        // 読み込み処理完了のコールバック
        private void LoadPeopleCompleted(LoadOperation<Person> op)
        {
            // エラー処理
            if (op.HasError)
            {
                op.MarkErrorAsHandled();
                MessageBox.Show("Error");
                return;
            }

            // キャンセルへの対応
            if (op.IsCanceled)
            {
                return;
            }

            // 取得したデータをEntityListに突っ込む
            // 自動でやってほしい・・・
            this.People.Source = op.Entities;

            // トータルの件数も手動で設定(これも自動でやってくれないの?)
            if (op.TotalEntityCount != -1)
            {
                this.PeopleView.SetTotalItemCount(op.TotalEntityCount);
            }
        }


    }
}

Viewの作成

上で作成したViewModelをViewに突っ込みます。XAMLでさくっとね。
ついでに、画面にDataGridとDataPagerを置いてUIを構築してます。Visual Studio 2010のデザイナでさくっと作りました。

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:l="clr-namespace:SilverlightApplication1"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
    <UserControl.Resources>
        <!-- ViewModelのインスタンス -->
        <l:MainPageViewModel x:Key="viewModel" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource viewModel}">
        <!-- DataGridとDataPagerにPeopleViewをバインドする -->
        <sdk:DataGrid AutoGenerateColumns="True" Margin="12,12,12,36" Name="dataGrid1" ItemsSource="{Binding Path=PeopleView}" />
        <sdk:DataPager Height="26" Margin="12,0,12,12" Name="dataPager1" PageSize="10" VerticalAlignment="Bottom" Source="{Binding Path=PeopleView}" />
    </Grid>
</UserControl>

以上で完成です。

実行結果

実行すると、ページングできるDataGridへのデータ表示がMVVMパターンで実現できたのがわかります。

ただ、正直な感想は若干コードが冗長になってる気がする…。