かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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パターンで実現できたのがわかります。

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