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クラスのフィールド値を使って検証しています。