Silverlight 4 におけるデータバインディングの強化 - IDataErrorInfo、 INotifyDataErrorInfo

皆様、こんにちは!

一昨日は、 Windows 7のアプリ投稿キャンペーンのお話しを、ZDNet BuilderのBlogの方に書いた ら、お陰様で大反響でしたw それに気を良くして、 PDC10パブリックビューイング の話も、同じように投稿してありますので、興味のある方は、ぜひご覧ください。こちらも大反響でSold Out必至なイベントです。ライブ演奏がありますよ!(しつこいかなw…)

さて、本日は、Silverlight 4におけるデータバインディングの強化点シリーズとして、IDataErrorInfo、 INotifyDataErrorInfoについて、ご紹介したいと思います。

Silverlight 4では、プロパティレベルでの妥当性検査のエラー通知としてIDataErrorInfo、及びエンティティレベルでの妥当性検査のエラー通知としてINotifyDataErrorInfoという機能が用意されています(後者はエンティティごと一括してエラーをハンドリングします)。

これは元々.NET Frameworkにもあるエラー検証(妥当性検査、バリデーション)のモデルを、Silverlightのユーザーインターフェースと対応させたものです。このエラー検証モデルは、データが入っているひとかたまり(エンティティ)の中で検証機能を実装するモデルです。

このあたりのモデルの理解は、 ソリューションサンプル-Silverlight 4 によるショッピングサイト構築 - でいつもご紹介しているWCF RIA Servicesの妥当性検査の仕組みの理解にも重要です。

また、例えば1,000画面等の大規模アプリケーション構築に役立つ、あるいはオフショア開発にも役立つ、そしてコンシューマー向けアプリケーションのように頻繁に画面のUpdateが発生する可能性がある場合の開発において極めて有用になる、MVVM (Model-View-ViewModel のような疎結合のアーキテクチャの理解の前提として、非常に重要になってきます。

参考 : MVVM (Model-View-ViewModel)とは、疎結合のアーキテクチャ パターンで、これを利用することにより、アプリケーションの振る舞いを、ユーザー インターフェイスから完全分離可能となります。WPF、Silverlight で利用可能です。デザイナーと開発者との完全な相互独立性を実現する可能性があると注目されています。詳細はこちらをご覧ください。

https://msdn.microsoft.com/ja-jp/magazine/ff798279.aspx

IDataErrorInfo の利用によるエラー検出

それでは、これも実際にアプリケーションを作ってみてみましょう。Visual Studio 2010を起動し、新しいプロジェクトでSilverlightアプリケーションを選びます。プロジェクト名を INotifyDataErrorInfoSample にして新規作成します。

MainPage.xamlのXAMLエディタを開いて、DesignHeightを"400"、DesignWidthを"500"に、それぞれ変更します。この中にTextBoxを2つ配置します。Widthは“380”でHeightは”100“にします。Labelを配置しContentプロパティの中身を”従業員名の入力“と変更します。

image

テキストボックスとラベルの配置

XAMLエディタで<UserControl>を選択し、プロパティウィンドウの中から、テキストを選び、ポイントを36ポイントに変更しておきます。

image

テキストのフォントサイズの変更

Silverlightのクライアント側に新しいクラスとしてEmployee.csを追加します。

image

Employeeクラスの追加

このクラスの実装を行います。まずはこの妥当性検証モデルを利用するためSystem.ComponentModelの名前空間をusing句で追加します。

System.ComponentModel名前空間の追加

 

 using System.ComponentModel; 

次に、下記のようにこのクラスを実装していきます。

Employeeクラスの実装

 

 namespace INotifyDataErrorInfoSample
{
    public class Employee:INotifyDataErrorInfo
    {
        private string lastName;
        public string LastName
        {
            get{return lastName;}
            set
            {
                lastName = value;
                this.OnErrorsChanged("LastName");
            }
        }

        private string firstName;
        public string FirstName
        {
            get{return firstName;}
            set
            {
                firstName = value;
                this.OnErrorsChanged("FirstName");
            }
        }

        // 1. INotifyDataErrorInfoメンバー準備
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        void OnErrorsChanged(string propertyName)
        {
            var d = this.ErrorsChanged;
            if (d!=null)
                d(this,new DataErrorsChangedEventArgs(propertyName));
        }

        // GetErrors 関数の実装 ②
        public System.Collections.IEnumerable GetErrors(string propertyName)
        {
            switch(propertyName)
            {
                case "FirstName":
                    if(!string.IsNullOrEmpty(firstName))
                        if(firstName.Length > 3)
                            return new[]{"姓が長すぎます"};
                    break;
                case "LastName":
                    if(!string.IsNullOrEmpty(lastName))
                        foreach(char c in lastName)
                        {
                            if(!(char.IsLetter(c))&& c!= ' ')
                                return new[]{"数字を含むことはできません"};
                        }
                    break;
             }
            return null;
        }

        // HasErrors の実装       ①
        public bool HasErrors
        {
            get {return firstName.Length > 3 || lastName !="";}

        }
    }
}

① TextBoxに入力した値の最初のチェックを行います。該当した場合にはエラーチェックの対象となります。

② ①で対象となったものがこのGetErrorsの対象となり再度チェックします。呼び出されたプロパティの内容と検証の内容により、それぞれエラーメッセージを出力しています。

ここまでがINotifyDataErrorInfoを使った妥当性検証機能付きのデータモデルの作成ということになります。これをどのようにして先ほどのSilverlightのUIであるXAMLと組み合わせるかが重要です(これが先述したMVVM (Model-View-ViewModel の基礎となる考え方です)。

MainPage.xamlを開いて、XAMLエディタで、TextBoxの箇所を下記のように編集します。

TextBoxへのTwoWayバインディングの適用

 <MainPage.xaml>
…
<TextBox Text="{Binding FirstName, 
    Mode=TwoWay}" Height="100" 
 HorizontalAlignment="Left" Margin="50,126,0,0" 
 Name="textBox1" VerticalAlignment="Top" Width="380" />
<TextBox Text="{Binding LastName, 
  Mode=TwoWay}" Height="100" 
 HorizontalAlignment="Left" Margin="50,261,0,0" 
 Name="textBox2" VerticalAlignment="Top" Width="380" />

この時点で、分離コード(MainPage.xaml.cs)内の処理は何もありませんが、このモデルがロジックのソースとなっていますので、下記のように、MainPage.xaml.csを書き換えます。DataContextが、このEmployeeであることを指定します。

DataContextにEmployeeクラスを指定

 <using System.Windows.Controls;

namespace INotifyDataErrorInfoSample
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            Employee employee = new Employee();
            this.DataContext = employee;
        }
    }
}

これでビルドを行い実行し、上下のTextBoxに適当な内容を入力すると、下記のような画面が出るはずです。

image

INotifyDataErrorInfoサンプル実行画面

この赤いメッセージの中身は先ほどの通り実装しましたが、メッセージを出すという処理は、分離コードの中では明示的には実装していません。INotifyDataErrorInfoを使った妥当性検証機能付きのデータモデルがSilverlightでも利用できることになったおかげで、このモデルとTextBoxをTwoWayのバインディングで結びつけるだけで、このような処理が可能となったのです。これはもちろん他のコントロールでもその特性に合わせて有効に利用できます。

以上です。いかがでしょうか?

非常に基本的かつ重要な内容ですし、これからの業務アプリ、エンタープライズアプリの開発において、前提として重要になるので、是非押さえておいて戴ければ幸いです。

鈴木 章太郎