前回の記事で、簡単なSilverlight2での入力値の検証を書いた。
[C#][Silverlight]Silverlightでの入力値の検証
今回は、ちょびっとだけ応用して、下のような画面を作ってみようと思う。
1つの画面に、2つの入力フォームがある形の画面です。
足し算ボタンは、その上にある2つのテキストボックスに整数値を入力してボタンを押すと足し算の結果をメッセージボックスで表示します。
入力を間違えている場合は、Errorというダイアログを出します。
下側の引き算ボタンも、同じような動きになります。
WPFなら、BindingGroupとかを使って上側と下側をわけるけど、Silverlight2には、そんな便利なものが無いので上側と下側をわけるためにちょいと工夫をしてみる。
下準備
SilverlightGroupValidationという名前でプロジェクトを作成する。
Page.xamlを下のようにして、画面の見た目を整える。
<UserControl x:Class="SilverlightGroupValidation.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="White">
<Border Margin="3" Padding="5" BorderBrush="DarkBlue" BorderThickness="3" CornerRadius="5">
<StackPanel>
<TextBlock Text="左辺値" />
<TextBox x:Name="textBoxPlusLhs" />
<TextBlock Text="右辺値" />
<TextBox x:Name="textBoxPlusRhs" />
<Button x:Name="buttonExecutePlus" Content="足し算" />
</StackPanel>
</Border>
<Border Margin="3" Padding="5" BorderBrush="DarkBlue" BorderThickness="3" CornerRadius="5">
<StackPanel>
<TextBlock Text="左辺値" />
<TextBox x:Name="textBoxMinusLhs" />
<TextBlock Text="右辺値" />
<TextBox x:Name="textBoxMinusRhs" />
<Button x:Name="buttonExecuteMinus" Content="引き算" />
</StackPanel>
</Border>
</StackPanel>
</UserControl>
この画面にバインドするためのデータを保持するPageModelという名前のクラスを作る。
テキストボックス4つぶんのデータを保持しないといけないので、プロパティを4つ作る。
using System.ComponentModel;
namespace SilverlightGroupValidation
{
// INotifyPropertyChangedのデフォルト実装
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class PageModel : NotifyPropertyChangedBase
{
#region PlusLhsプロパティ
private int _plusLhs;
public int PlusLhs
{
get
{
return _plusLhs;
}
set
{
_plusLhs = value;
OnPropertyChanged("PlusLhs");
}
}
#endregion
#region PlusRhsプロパティ
private int _plusRhs;
public int PlusRhs
{
get
{
return _plusRhs;
}
set
{
_plusRhs = value;
OnPropertyChanged("PlusRhs");
}
}
#endregion
#region MinusLhsプロパティ
private int _minusLhs;
public int MinusLhs
{
get
{
return _minusLhs;
}
set
{
_minusLhs = value;
OnPropertyChanged("MinusLhs");
}
}
#endregion
#region MinusRhsプロパティ
private int _minusRhs;
public int MinusRhs
{
get
{
return _minusRhs;
}
set
{
_minusRhs = value;
OnPropertyChanged("MinusRhs");
}
}
#endregion
}
}
このPageModelクラスを、PageのDataContextにセットする。
using System.Windows.Controls;
namespace SilverlightGroupValidation
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
DataContext = new PageModel();
}
public PageModel Model
{
get { return DataContext as PageModel; }
}
}
}
そして、画面側でTextBoxのTextプロパティにバインドをする。
<UserControl x:Class="SilverlightGroupValidation.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="White">
<Border Margin="3" Padding="5" BorderBrush="DarkBlue" BorderThickness="3" CornerRadius="5">
<StackPanel x:Name="stackPanelPlus" BindingValidationError="stackPanelPlus_BindingValidationError">
<TextBlock Text="左辺値" />
<TextBox x:Name="textBoxPlusLhs"
Text="{Binding PlusLhs, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<TextBlock Text="右辺値" />
<TextBox x:Name="textBoxPlusRhs"
Text="{Binding PlusRhs, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<Button x:Name="buttonExecutePlus" Content="足し算" />
</StackPanel>
</Border>
<Border Margin="3" Padding="5" BorderBrush="DarkBlue" BorderThickness="3" CornerRadius="5">
<StackPanel x:Name="stackPanelMinus" BindingValidationError="stackPanelMinus_BindingValidationError">
<TextBlock Text="左辺値" />
<TextBox x:Name="textBoxMinusLhs"
Text="{Binding MinusLhs, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<TextBlock Text="右辺値" />
<TextBox x:Name="textBoxMinusRhs"
Text="{Binding MinusRhs, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<Button x:Name="buttonExecuteMinus" Content="引き算" />
</StackPanel>
</Border>
</StackPanel>
</UserControl>
上記のXAMLを見ると、stackPanelPlusとstackPanelMinusにBindingValidationErrorというイベントハンドラを作成している。
このイベントは、バインディングでエラーが出たときに呼ばれる。
しかも、ルーティングイベントなので子要素で起きたイベントは、基本的に親要素で呼べるようになっている。
これで、入力フォームごとに独自の入力値エラー処理がかける。
// 足し算用入力フォームにあるエラーの数
private int plusErrorCounter;
// 足し算の入力値が不正の場合に呼ばれるイベント
private void stackPanelPlus_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
ValidationError(e, ref plusErrorCounter);
}
// 引き算用入力フォームにあるエラーの数
private int minusErrorCounter;
// 引き算の入力値が不正の場合に呼ばれるイベント
private void stackPanelMinus_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
ValidationError(e, ref minusErrorCounter);
}
private void ValidationError(ValidationErrorEventArgs e, ref int errorCounter)
{
e.Handled = true;
// 入力値のエラーのイベントを発行したコントロールを取得
var element = (Control)e.OriginalSource;
switch (e.Action)
{
case ValidationErrorEventAction.Added:
// エラーが追加された場合はエラーカウントをあげて色をつける
errorCounter++;
element.Background = new SolidColorBrush(Colors.Orange);
ToolTipService.SetToolTip(element, e.Error.Exception.Message);
break;
case ValidationErrorEventAction.Removed:
// エラーが消えた場合はエラーカウントをさげて色をなくす
errorCounter--;
element.Background = null;
ToolTipService.SetToolTip(element, null);
break;
}
}
そして、エラーが起きたときには、エラーの個数をカウントする変数をカウントアップしている。
エラーが消えたときは、逆にカウントを下げている。これでエラーのカウントが0の場合に、処理を実行すればいいということになる。
ということで、早速ボタンのクリックイベントの実装になる。イベントハンドラの登録は省略して、各々のエラーカウンターの値を確認して計算を行う。
private void buttonExecutePlus_Click(object sender, RoutedEventArgs e)
{
if (plusErrorCounter != 0)
{
// エラーがあればエラーメッセージを表示
MessageBox.Show("Error");
return;
}
// 無ければ計算
MessageBox.Show(Model.PlusLhs + Model.PlusRhs + "");
}
private void buttonExecuteMinus_Click(object sender, RoutedEventArgs e)
{
if (minusErrorCounter != 0)
{
// エラーがあればエラーメッセージを表示
MessageBox.Show("Error");
return;
}
// 無ければ計算
MessageBox.Show(Model.MinusLhs - Model.MinusRhs + "");
}
これで入力フォームごとに、入力値の検証がおこなわれているような動きをする。
動作確認
実行して動きを確認してみた。まず、足し算の部分に正しい値を入力してボタンを押す。ちゃんと計算できているのがわかる。
次に、足し算の数字を入力する部分に「あいうえお」と入力して足し算ボタンを押してみた。
ツールチップもちゃんと出てる。
この状態で引き算のボタンを押しても、関係なく動く。
非常にベタな書き方だけど、複数の入力フォームがあるような画面は、こういう形でいいのじゃないだろうかと思った今日この頃でした。