というわけで、Validationについて勉強することにします。
個人的には、興味をそそられない部分であるバリデーション(だって実際にバリデーションしかけるのって田植え作業みたいでめんどくさいし)。
WPFではどうなってるのかというと…BindingオブジェクトにValidationRulesというプロパティがあるので、そこで指定するみたいです。
Validationについて勉強しだすまえに、足場となるプロジェクトを1つでっちあげます。
今回は、真ん中にテキストボックスが置いてあって、画面の下にあるボタンを押すとテキストボックスに入力された内容が出力されるだけのシンプルな画面。
ここに入力された値についてValidationしてみたいと思います。
あと、めんどくさいのでWindow1のDataContextにはthisを突っ込んでいます。
こうすると、自分のフィールドへのバインドが楽チン。(作法的にどうだろうというのは今回は考えない)
Window1.xaml
<Window x:Class="WpfValidate.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Validation" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100">
<TextBox.Text>
<Binding Path="TargetValue" UpdateSourceTrigger="PropertyChanged">
</Binding>
</TextBox.Text>
</TextBox>
<Button Grid.Row="1" Content="Alert!" Click="Button_Click" />
</Grid>
</Window>
Window1.xaml.cs
using System.Windows;
namespace WpfValidate
{
public partial class Window1 : Window
{
// TextBoxへバインドする変数
// 今回は、コントロールからソースへアップデートするだけのものなので
// INotifyPropertyChangedは実装しない
public int TargetValue { get; set; }
public Window1()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(TargetValue.ToString());
}
}
}
これを実行すると、下のように動く。
数字を入力してAlert!ボタンを押すとメッセージボックスが出る。
上の状態からテキストボックスの中身を「12a」にしてAlert!を押すと下のようになる。
数値に変換できないので、直前の値が入りっぱなし。
これがデフォのうごきっぽい。
ということで、バリデーションを追加してみようと思います。
一番お手軽なのは、例外出たら駄目だよっていうバリデーション。
その名も、「ExceptionValidationRule」です。
さくっとBinding.ValidationRulesに追加します。
<Window x:Class="WpfValidate.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Validation" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100">
<TextBox.Text>
<Binding Path="TargetValue" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button Grid.Row="1" Content="Alert!" Click="Button_Click" />
</Grid>
</Window>
この状態で実行して「12a」とか入力すると、下のように入力値が不正だと赤枠で囲まれるようになります。
このExceptionValidationRuleは、どうやら特別扱いされてるみたいで、MSDNを読み漁ってると下のような記述がありました。
http://msdn2.microsoft.com/ja-jp/library/ms752347.aspx#validation_process
バインドに関連付けられた ExceptionValidationRule があり、手順 4. で例外がスローされた場合、バインディング エンジンは UpdateSourceExceptionFilter が存在するかどうかをチェックします。UpdateSourceExceptionFilter コールバックを使用して、例外を処理するためのカスタム ハンドラを提供することもできます。UpdateSourceExceptionFilter が...
ふむふむ、UpdateSourceExceptionFilterっていうものがあるのね。どうやら、このコールバックでnullを返すとかやるとエラーを無視ったりできるみたいだ。
ここら辺は入門っぽくないのでとりあえずスルー。存在だけ知っておこう。
気を取り直して、今度は自前ValidationRuleを作ってみようと思う。
これの作り方は非常に簡単。ValidationRuleクラスを継承して、Validateメソッドをオーバーライドする。
ためしに偶数のみOKなValidationRuleを作ってみた。名前はMyValidationRuleにしました。
using System.Windows.Controls;
namespace WpfValidate
{
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var inputValue = value as string;
if (inputValue == null)
{
return new ValidationResult(false, "おかしい");
}
int parsedValue = 0;
if (!int.TryParse(inputValue, out parsedValue))
{
return new ValidationResult(false, "数値じゃない");
}
if (parsedValue % 2 != 0)
{
return new ValidationResult(false, "偶数じゃない");
}
return ValidationResult.ValidResult;
}
}
}
これをExceptionValidationRuleの代わりに仕掛けてみます。
<Window x:Class="WpfValidate.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfValidate="clr-namespace:WpfValidate"
Title="Validation" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Name="textBox" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100">
<TextBox.Text>
<Binding Path="TargetValue" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<WpfValidate:MyValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button Grid.Row="1" Content="Alert!" Click="Button_Click" />
</Grid>
</Window>
これを実行すると下のようになりました。
数値の偶数のみ通すようになってる。
ばっちりっぽい。
Validationは、まだまだ調べることがありそうだ…Errorのときのテンプレートや、Validation.Errorイベントや…
眠いのでまた後日。