Silverlight3の正式版も出たので、ぼちぼち触ってみています。
まとまった時間が最近なかなかとれないので、エントリにするまでには至ってないのですが、今日はちょっくら入力値の検証について書いてみようと思います。
基本的には、C#のコード的には、プロパティに値がセットされるタイミングで気に入らない値が入ってきたら例外を投げるというスタンスはSilverlight2の頃から変わっていません。
ただ、Silverlight3では、この操作をちょっと簡単に出来るように色々と工夫が張り巡らされています。
Silverlight3で入力検証がどうなるかということを示すために、簡単なサンプルを作ってみようと思います。
SL3ValidationSampleという名前でSilverlightアプリケーションを作成します。
ここに、Silverlight2の頃と同じような入力値の検証をやるクラスOldPersonを作成します。
この、OldPersonクラスには、FullNameというプロパティがあり、必須入力で、10文字以内で入力する必要があります。
特に難しいこともないので、さくっと作っていきます。
using System;
using System.ComponentModel;
namespace SL3ValidationSample
{
public class OldPerson : INotifyPropertyChanged
{
private string _fullName;
public string FullName
{
get { return _fullName; }
set
{
if (Equals(_fullName, value)) return;
// 必須入力チェック
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("名前を入力してください");
}
// 長さチェック
if (value.Length > 10)
{
throw new ArgumentException("名前は10文字以下で入力してください");
}
// 正しい値なので、セットして変更通知
_fullName = value;
OnPropertyChanged("FullName");
}
}
#region INotifyPropertyChanged メンバ
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
var h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
}
こいつを画面に表示するとなると
<UserControl x:Class="SL3ValidationSample.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:local="clr-namespace:SL3ValidationSample"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<StackPanel x:Name="LayoutRoot">
<Grid>
<Grid.DataContext>
<local:OldPerson FullName="田中 太郎" />
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="250" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0" Grid.Column="0"
Text="名前" />
<TextBox
Grid.Row="0" Grid.Column="2"
Text="{Binding FullName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
</Grid>
<Button Content="Dummy" />
</StackPanel>
</UserControl>
こんな感じになるはず。
実行すると…
こんな感じになります。
同じもの+αの機能がついたものをSilverlight3の流儀?で作ってみようと思います。
同じプロジェクトにNewPersonという名前のクラスを作成します。
そして、プロジェクトにSystem.ComponentModel.DataAnnotationsの参照を追加します。
System.ComponentModel.DataAnnotationsには、データの検証をするための便利クラスやアノテーションが入っています。
アノテーションにはRangeAttributeやStringLengthAttributeやRequiredAttributeなど、名前を見ただけで大体どんなことをしてくれるのかわかりそうな奴らが入ってます。
とりあえず、このSystem.ComponentModel.DataAnnotationsにあるクラスを使うとOldPersonと同じような動きをするものは以下のように書けます。
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace SL3ValidationSample
{
public class NewPerson : INotifyPropertyChanged
{
private string _fullName;
[Display(Name="名前", Description="10文字以内で入力してください")]
[Required(ErrorMessage="名前を入力してください")]
[StringLength(10, ErrorMessage="名前は10文字以内で入力してください")]
public string FullName
{
get { return _fullName; }
set
{
if (Equals(_fullName, value)) return;
// プロパティについてるアノテーションに従って値の検証してください
var ctx = new ValidationContext(this, null, null);
ctx.MemberName = "FullName";
Validator.ValidateProperty(value, ctx);
// 因みに上の3行をを一行で書くと
// Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "FullName" });
_fullName = value;
OnPropertyChanged("FullName");
}
}
#region INotifyPropertyChanged メンバ
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
var h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
}
表示するためのXAMLも以下のようになります。
<!--
xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"
-->
<Grid>
<Grid.DataContext>
<local:NewPerson FullName="田中 太郎" />
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="250" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<dataInput:Label
Grid.Row="0" Grid.Column="0"
Target="{Binding ElementName=textBoxName}"/>
<TextBox
x:Name="textBoxName"
Grid.Row="0" Grid.Column="2"
Text="{Binding FullName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
<dataInput:DescriptionViewer
Grid.Row="0" Grid.Column="3"
Target="{Binding ElementName=textBoxName}" />
</Grid>
XAMLのほうもSilverlight3で追加されたものを使ってます。
System.Windows.Controls.Data.InputアセンブリにあるLabelとDescriptionViewerを使っています。どちらもTargetプロパティに対象のコントロールをバインドするか、PropertyPathプロパティに、対象のプロパティ名を指定して使います。
Labelを使うと、妥当性検証エラーがあるさいに赤色になったり、必須入力項目の場合に太字になったりするみたいです。
DescriptionViewerは、バインドされているプロパティのDisplayAttributeのDescriptionに指定した文字列がツールチップで表示されます。
DescriptionViewerコントロールのツールチップと通常時のラベル
バリデーションエラー時の表示
バリデーションエラーがあっても別にDescriptionViewerは特に赤色になるとかは無いみたい
System.Windows.Controls.Data.Inputには、LabelとDescriptionViewer以外にValidationSummaryというものがあります。
これは名前が示すとおりバリデーションエラーを一覧表示してくれます。
どこかしらに<dataInput:ValidationSummary />を置いた様子
ValidationSummaryに表示されているエラーをクリックすると、該当するコントロールにフォーカスが移動します。
上の画像だとFullName 名前を入力してくださいを選んだので、上側のテキストボックスにフォーカスがいってます。(画像ではわかりにくいですが・・・)
ということで、Silverlight3では、データ入力系の画面を作るうえで、便利なコントロールとAttributeが用意されていますという紹介でした。
いい感じかな・・・?