WPFプログラミング備忘録

WPF ValidationRuleクラスを使ってデータの妥当性検証をする

WPF

はじめに

この記事ではValidationRuleクラスを使って入力データの妥当性検証を行う方法を確認します。

プロジェクトのファイル構成は下図のとおりです。

開発環境は以下のとおりです。

オペレーティングシステムWindows10 x64
Visual StudioMicrosoft Visual Studio Community 2019 Version 16.11.2
.NET Framewrok4.7.2

動作の仕様

動作の仕様は、TextBoxコントロールに100未満の正の整数が入力された場合は妥当性検証は成功とし、それ以外の数値等が入力された場合は失敗とします。

成功時のウィンドウは以下のとおりです。

失敗時のウィンドウは以下のとおりとします。

  • 赤い枠線を表示する
  • 背景を薄いピンク色にする
  • 右側にエラーメッセージを表示する
  • ツールチップにエラーメッセージを表示する

ValidationRuleクラスを使用する

バインディングソースとして使用するPositiveNumberプロパティを定義したValidatingNumber.csは以下のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfValidatingData2
{
    class ValidatingNumber
    {
        public int PositiveNumber { get; set; }
    }
}

以下のMinNumberRule.csでは、ValidationRule抽象クラスを継承しValidate抽象メソッドをオーバーライドすることによってカスタムルールを定義します。このような方法で実装するのはWPFの決まりです。

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace WpfValidatingData2
{
    class MinNumberRule : ValidationRule
    {
        private const string MESSAGE = "100未満の正の整数を入力してください";
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            try
            {
                string val = (string)value;

                int inputNumber = string.IsNullOrWhiteSpace(val) ? -1 : int.Parse(val);

                if (inputNumber < 1 || inputNumber > 99)
                {
                    // 失敗時
                    return new ValidationResult(false, MESSAGE);
                }
                // 成功時
                return ValidationResult.ValidResult;
            }
            catch (Exception)
            {
                // 数値以外の文字やintの最大値より大きい数値が入力された場合など
                return new ValidationResult(false, MESSAGE);
            }
        }
    }
}

XAMLファイルは以下のとおりです。

<Window x:Class="WpfValidatingData2.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:WpfValidatingData2"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="600">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Background" Value="LightPink"/>
                    <Setter Property="ToolTip" 
                            Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
                                                        Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <ControlTemplate x:Key="_errorTemplate">
            <StackPanel Orientation="Horizontal">
                <Border BorderBrush="Red" BorderThickness="2" Margin="0,0,6,0">
                    <AdornedElementPlaceholder x:Name="_el"/>
                </Border>
                <TextBlock Text="{Binding AdornedElement.(Validation.Errors)[0].ErrorContent, ElementName=_el}"
                           Foreground="Red" HorizontalAlignment="Right"
                           VerticalAlignment="Center" Margin="0,0,10,0"/>
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="240"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="1" Text="正の整数 : " FontSize="20" TextAlignment="Right" Margin="10"/>
        <TextBox Grid.Row="1" Grid.Column="1" FontSize="20" Margin="2"
                 Validation.ErrorTemplate="{StaticResource _errorTemplate}">
            <TextBox.Text>
                <Binding Path="PositiveNumber" UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:MinNumberRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
    </Grid>
</Window>

プロパティ要素構文を使ってTextBox.TextにBindingインスタンスを定義します。ここではマークアップ拡張構文は使えません。Binding.ValidationRulesにはカスタムルールを定義したMinNumberRuleインスタンスを設定します。

リソースで定義しているAdornedElementPlaceholderを含むカスタムテンプレート_errorTemplateはTextBoxの右側にエラーメッセージを表示するためのものです。詳細については以下の記事をご確認ください。

>> WPF データの妥当性検証をしたい

コードビハインドは以下のとおりです。DataContextを設定しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfValidatingData2
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new ValidatingNumber { PositiveNumber = 5 };
        }
    }
}

以上の実装で仕様どおりの動作をすることがわかります。

その他詳細については以下の記事などをご確認ください。

方法: バインディングの検証の実装 - WPF .NET Framework
Windows Presentation Foundation (WPF) で、無効な値が入力されたときにバインディングの検証を使用してユーザーに視覚的フィードバックを提供する方法について説明します。

今回はValidationRuleクラスを使って入力データの妥当性検証を行う方法について確認しました。

以上です。

コメント