TextBoxなどの入力値検証でValidationRuleを継承したクラスを作ることが多いですよね。 たいていの場合はxamlで追加します。
<TextBox>
<TextBox.Text>
<Binding>
<Binding.ValidationRules>
<local:なんたらValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
xamlでValidationRuleを追加するコードを書いた場合、自作ValidationRuleはどこかで勝手にインスタンス化されます。 このインスタンスにアクセスできれば、次のようなことが可能になります。
- 検証の閾値を動的に設定。
- 他のクラスに持たせた値を検証に使用。
ValidationRuleのインスタンスを探すには、Bindingクラスのインスタンスからたどっていきます。 例えば、xamlで<TextBox Name="textBox"/>と書いて作ったTextBoxのBindingは、
Binding textBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty);
BindingのプロパティであるValidationRulesコレクションに自作ValidationRuleが収まっています。 そのコレクションから登録したルールを探し出せばあれこれ複雑な検証が可能...
ってちょっとコード量が多くなりますよね。 xamlで追加して探すより、C#のコードでValidationRuleのインスタンスを追加した方が早そうです。
Binding textBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); なんたらValidationRule validationRule = new なんたらValidationRule(); textBinding.ValidationRules.Add(validationRule);
ValidationRuleへの参照をとっておけば、あれこれ複雑な検証が可能になります。
ちなみに、バインドした値を検証する機会はValidationRule以外にもあります。 プロパティのsetterなどです。 プロパティのsetterでの検証は多くの場合必須になります。 どちらで検証するのが筋が通っているかとか、コードが短くなるかとか、よく考えた方がいいかもしれませんね?
入力値の検証については、前の投稿でもちょっと書きました。 参考になるかもしれないので、ヒマな人はどうぞ。
- 前の投稿 ... wpf 設定ダイアログの作り方
以下、サンプルコードです。 まずはMainWindow.xaml。
<Window x:Class="AddValidationRuleOnCS.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <Style TargetType="TextBox"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="ToolTip"> <Setter.Value> <Binding Path="(Validation.Errors)[0].ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" /> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <TextBox Name="textBox" Text="{Binding ElementName=textBlock, Path=Text, UpdateSourceTrigger=PropertyChanged }" /> <TextBlock Margin="20,4">↓検証済み文字列</TextBlock> <TextBlock Name="textBlock"/> </StackPanel> </Window>
TextBoxに文字を入力すると、検証に通ったものだけが下のTextBlockに表示されます。 検証を通らなかった場合、TextBoxの文字にマウスカーソルを合わせるとポップアップでエラーメッセージが表示されます。
C#のコードでValidationRuleを追加するということで、xamlにはBinding.ValidationRules要素を書いていません。 ちょっとだけスッキリ。
次はMainWindow.xaml.csです。
// MainWindow.xaml.cs using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace AddValidationRuleOnCS { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Binding textBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); TestValidationRule validationRule = new TestValidationRule(this); textBinding.ValidationRules.Add(validationRule); } public int TextMaxLength = 10; } }
コンストラクタで自作のValidationRuleを追加しています。 TextMaxLengthフィールドはTestValidationRuleから使います。 本来なら、固定数値を渡すだけならTestValidationRuleにプロパティを追加すればいいだけなんですが、今回はサンプルって事で簡単なものにしました。
最後にTestValidationRule.csです。
// TestValidationRule.cs using System.Globalization; using System.Windows.Controls; namespace AddValidationRuleOnCS { class TestValidationRule : ValidationRule { private MainWindow _owner; public TestValidationRule(MainWindow owner) { _owner = owner; } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if (!(value is string)) return new ValidationResult(false, "文字列じゃない"); string param = (string)value; if(_owner.TextMaxLength < param.Length) return new ValidationResult(false, "文字列長すぎ"); return new ValidationResult(true, null); } } }
MainWindowクラスのフィールド値を使って検証しています。