WPF/XAML : TextBox の入力内容を検証して不正入力の場合にエラーを表示する
ポイント
- TextBox.Text に Binding.ValidationRules で Validation のルールを設定する
- TextBox.ErrorTemplate で不正入力時の表示をカスタマイズできる
- デフォルトではテキストボックスに赤枠表示
- AdornedElementPlaceholder の中に元のテキストボックスが含まれている
このスクリーンショットのような表示をするサンプルを以下に示します。
全体の xml
最低限エラーがわかることが良いだけであれば、ErrorTemplate も Style も設定不要なので Windows.Resources 部分の定義はいりません。
TextBox.Text 内の Binding で Path と UpdateSourceTrigger を定義セットし、ValidationRules の中に自作の ValidationRule を継承したクラスを入れるだけで、検証失敗時の赤枠表示は有効になります。
<Window.Resources> <!-- エラー時にテキストボックスの右の方に ! を表示するテンプレート --> <ControlTemplate x:Key="ExclamationOnError"> <Grid> <!-- FontSize を元のテキストボックスから取得するために名前をつけて Binding --> <AdornedElementPlaceholder x:Name="TextBox"/> <TextBlock Text="! " HorizontalAlignment="Right" Foreground="Red" FontSize="{Binding ElementName=TextBox, Path=AdornedElement.FontSize}"/> </Grid> </ControlTemplate> <!-- Validation がエラーを返した際にその内容をツールチップを表示するスタイル --> <Style x:Key="TextBoxHasError" TargetType="{x:Type TextBox}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <!-- ErrorTemplate に 上で定義した Template を設定 --> <TextBox Width="100" Grid.Row="0" Grid.Column="0" Margin="8" Validation.ErrorTemplate="{StaticResource ExclamationOnError}" Style="{StaticResource TextBoxHasError}"> <TextBox.Text> <Binding Path="Text1" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:NumberValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <!-- 同上 + FrontSize を大きくした版 --> <TextBox Width="100" Grid.Row="1" Grid.Column="0" Margin="8" FontSize="36" Validation.ErrorTemplate="{StaticResource ExclamationOnError}" Style="{StaticResource TextBoxHasError}"> <TextBox.Text> <Binding Path="Text2" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:NumberValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <!-- ErrorTemplate を設定しない版。赤枠が表示される --> <TextBox Width="100" Grid.Row="2" Grid.Column="0" Margin="8" Style="{StaticResource TextBoxHasError}"> <TextBox.Text> <Binding Path="Text3" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:NumberValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> </Grid>
ValidationRule クラス
class NumberValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if( ((string)value).Any(c => !char.IsNumber(c))) { return new ValidationResult(false, "Invalid character."); } else { return new ValidationResult(true, null); } } }
MainWindow クラス
public partial class MainWindow : Window { public string Text1 { get; set; } public string Text2 { get; set; } public string Text3 { get; set; } public MainWindow() { InitializeComponent(); // DataContext = this; } }