WPFの勉強を進めると DataBindingの活用に 大きな特徴があり、入力データの検証でも活用するのが一般的なやり方のようです。
従来 自己流で行っていた直接UI要素をゴリゴリいじくる方法は、UI要素とビジネスロジックを疎結合にしたい との流れから WPFの流儀に反しイケテナイ方法のようです。ようやく 自分なりに理解できる 検証方法にたどり着いたので POSTします。実現した処理は、エラーになったTextBoxの背景色をピンクにエラー内容をToolTipに表示することです。
作成したWindow
テキストボックスとボタンのみの画面
・ボタンはフォーカス移動のためダミーで配置
・テキストボックス:正の整数のみOK
・エラー時の処理 背景色をピンクに、ToolTipにエラー内容を表示
MainWindow.xaml
<Window x:Class="WpfApplication5CS.MainWindow" 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:WpfApplication5CS" mc:Ignorable="d" Title="MainWindow" Height="250" Width="400"> <Window.Resources> <Style TargetType="TextBox"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/> <Setter Property="Background" Value="#ffeeff" /> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="50"/> <RowDefinition Height="Auto"/> <RowDefinition Height="50"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="100"/> </Grid.ColumnDefinitions> <TextBox x:Name="TextBox" VerticalAlignment="Top" Grid.Column="1" Grid.Row="1" FontSize="18" Text="{Binding ID, ValidatesOnDataErrors=True}" /> <Button x:Name="button" Content="ボタン(ダミー)" Grid.Column="1" Margin="0" Grid.Row="3" VerticalAlignment="Top" FontSize="18"/> </Grid> </Window>
Window.Resourcesで Target:TextBoxにエラーがあれば、ToolTipにエラー内容を表示し、背景色をピンクにすることを指定しています。
TextBoxの定義では、DataContexのプロパティ:IDにバウンドしデータエラーの検出を行うことを指定しています。
MainWindow.xaml.cs
using System.Windows; namespace WpfApplication5CS { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // InitializeComponent() 呼び出しの後で初期化を追加します。 this.DataContext = new DataSource(); } } }
DataContextにDataSourceクラスを用いることを追加しただけで、VisualStudioのテンプレートをそのまま使っています。
DataSource.cs DataContextに指定したクラスです。
using System; using System.ComponentModel; namespace WpfApplication5CS { class DataSource: IDataErrorInfo { public String ID { get; set; } // 今回は使わないが、IDataErrorInfo インターフェースでは実装しなければならない public string Error { get { return null; } } // これも実装必須のプロパティで、各プロパティに対応するエラーメッセージを返す public string this[string propertyName] { get { string result = null; switch (propertyName) { case "ID": if (this.ID == null) return null; int ii; try { ii = int.Parse(this.ID); } catch (Exception e) { result = "IDは整数値を入力してください。"; break; } if (ii < 0) result = "IDは0以上の整数値を入力してください。"; break; } return result; } } } }
IDをintで定義して setアクセサーで直接代入してもほぼ同様の結果になりますが、初期画面を表示した際 エラー状態になることを回避するためこのような処理を行っています。
DataBindingなんて、きっとAccessが登場した時からある DataBindみたいなものだろう とタカをくくっていた のぼったにとっては、目が点になることばかり。 ようやく 流儀に少しはかなうデータ検証方法が実装できました。これでどんなプログラムを作ろうか?
参考にしたURL