例外を利用したデータ検証

 WPFではデータの検証を行う方法が複数用意されています。
 今回はその中でも一番単純な例外を利用したデータ検証の方法を紹介します。
 例外を利用したデータ検証では、プロパティのset時に値のチェックを行い、問題がある場合は例外を発生させます。
 あとは、View側で例外メッセージを取得して、エラーメッセージとして表示します。
 View側のエラーメッセージ表示は他のデータ検証でもほぼ同じです。
 それでは、まずはViewModelのサンプルコードを見てみましょう。
using Livet;
using System;

namespace Validation1.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {

        #region Value1変更通知プロパティ
        private int _Value1;

        public int Value1
        {
            get
            { return _Value1; }
            set
            { 
                if (_Value1 == value)
                    return;
                _Value1 = value;

                // データ検証
                if(value < 0)
                {
                    throw new Exception("0以上の数値を入力してください。");
                }

                RaisePropertyChanged();
            }
        }
        #endregion


        #region Value2変更通知プロパティ
        private int _Value2;

        public int Value2
        {
            get
            { return _Value2; }
            set
            { 
                if (_Value2 == value)
                    return;
                _Value2 = value;

                // データ検証
                if (value < 0)
                {
                    throw new Exception("0以上の数値を入力してください。");
                }

                RaisePropertyChanged();
            }
        }
        #endregion


        #region Value3変更通知プロパティ
        private int _Value3;

        public int Value3
        {
            get
            { return _Value3; }
            set
            { 
                if (_Value3 == value)
                    return;
                _Value3 = value;

                // データ検証
                if (value < 0)
                {
                    throw new Exception("0以上の数値を入力してください。");
                }

                RaisePropertyChanged();
            }
        }
        #endregion

    }
}
 Value1、Value2、Value3と3つのプロパティを定義しています。
 どのプロパティも値をチェックして0未満の場合は例外を発生させています。
 同じ様なプロパティを複数作ったのは、View側で表示方法を複数紹介するためです。
 次に、Viewのサンプルコードを見てみましょう。
<Window x:Class="Validation1.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:Validation1.Views"
        xmlns:vm="clr-namespace:Validation1.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    
    <Window.Resources>
        <!--TextBoxの右側にエラーメッセージを表示-->
        <ControlTemplate x:Key="ErrorTemplate">
            <DockPanel>
                <TextBlock DockPanel.Dock="Right" Foreground="Red" Margin="5,0"
                           Text="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
                
                <!--AdornedElementPlaceholderはErrorTemplateが適用される要素のことです-->
                <Border BorderBrush="Red" BorderThickness="1"
                        Width="{Binding ElementName=adornedElement, Path=ActualWidth}"
                        Height="{Binding ElementName=adornedElement, Path=ActualHeight}">
                    <AdornedElementPlaceholder Name="adornedElement"/>
                </Border>
            </DockPanel>
        </ControlTemplate>
        
        <!--ツールチップにエラーメッセージを表示する-->
        <Style x:Key="ToolTipErrorStyle" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <Binding RelativeSource="{RelativeSource Self}" Path="(Validation.Errors)[0].ErrorContent"/>
                        </Setter.Value>
                    </Setter>
                </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"/>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="0" Grid.Column="0" Text="エラーメッセージを表示:"/>
        <TextBox Grid.Row="0" Grid.Column="1"
                 Validation.ErrorTemplate="{StaticResource ErrorTemplate}"
                 Text="{Binding Value1, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"/>
        
        <TextBlock Grid.Row="1" Grid.Column="0" Text="ツールチップに表示:"/>
        <TextBox Grid.Row="1" Grid.Column="1" Style="{StaticResource ToolTipErrorStyle}"
                 Text="{Binding Value2, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"/>
        
        <TextBlock Grid.Row="2" Grid.Column="0" Text="メッセージを別要素に表示:"/>
        <TextBox Grid.Row="2" Grid.Column="1"
                 Text="{Binding Value3, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
                 Validation.ValidationAdornerSite="{Binding ElementName=ErrorMessageText}"/>
        <TextBlock Grid.Row="3" Grid.Column="2" Name="ErrorMessageText"
                   Text="{Binding RelativeSource={RelativeSource Self}, 
                    Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)[0].ErrorContent}"
                   Foreground="Red"/>
    </Grid>
</Window>
 このコードを実行し、設定した範囲外の数値を入力すると以下の様になります。
データ検証1
 例外を利用してデータ検証を行う場合は、検証する値をバインディングする際に「ValidatesOnExceptions」をtrueにする必要があります。
 このサンプルコードでは「UpdateSourceTrigger」をPropertyChangedにしていますが、これは値が変化した瞬間にデータ検証を行う為です。どのタイミングで検証を行うかはケースバイケースだと思うので、適したタイミングで更新するようにしてください。
 「ValidatesOnExceptions」をtrueにしただけでは、エラーメッセージを表示できません。
 エラーメッセージを表示するためには、ControlTemplateやStyleを使用して何らかの方法でエラーメッセージを表示させるような工夫が必要になります。
 最初の項目はエラーテンプレートを変更することで、エラーメッセージを表示させています。
 
<ControlTemplate x:Key="ErrorTemplate">
    <DockPanel>
        <TextBlock DockPanel.Dock="Right" Foreground="Red" Margin="5,0"
                Text="{Binding ElementName=adornedElement, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>

        <!--AdornedElementPlaceholderはErrorTemplateが適用される要素のことです-->
        <Border BorderBrush="Red" BorderThickness="1"
            Width="{Binding ElementName=adornedElement, Path=ActualWidth}"
            Height="{Binding ElementName=adornedElement, Path=ActualHeight}">
            <AdornedElementPlaceholder Name="adornedElement"/>
        </Border>
    </DockPanel>
</ControlTemplate>
 AdornedElementPlaceholderがエラーテンプレートが適用される要素を表しています。(このサンプルの場合はTextBoxになります)
 AdornedElementPlaceholderをBorderで囲い、赤枠表示にさせています。(標準のエラーテンプレートと同じような見た目にしています。)
 エラーメッセージの表示は、AdornedElementPlaceholderの右側にTextBlockで表示させています。
 バインディング対象がちょっとややこしいことになっていますが、定型文なのでなんとか覚えてください。

 エラーテンプレートを使わず、スタイルでエラーメッセージを表示することもできます。
 2つ目の項目は、スタイルを使用してツールチップにエラーメッセージを表示させています。
<Style x:Key="ToolTipErrorStyle" TargetType="{x:Type TextBox}">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip">
                <Setter.Value>
                    <Binding RelativeSource="{RelativeSource Self}" Path="(Validation.Errors)[0].ErrorContent"/>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>
 エラーがあるかどうかはValidation.HasErrorの値を使って見分けることができます。この値をトリガーとしてエラーがある場合はツールチップにエラーメッセージを表示させています。
 エラーメッセージの場所は、これまたちょっとややこしいことになっていますが、これも定型文なので頑張って覚えてください。

 3つ目の項目はエラーメッセージを別の要素に表示させる方法です。
<TextBox Grid.Row="2" Grid.Column="1"
            Text="{Binding Value3, ValidatesOnExceptions=True, UpdateSourceTrigger=PropertyChanged}"
            Validation.ValidationAdornerSite="{Binding ElementName=ErrorMessageText}"/>
<TextBlock Grid.Row="3" Grid.Column="2" Name="ErrorMessageText"
            Text="{Binding RelativeSource={RelativeSource Self}, 
            Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)[0].ErrorContent}"
            Foreground="Red"/>
 値を入力するTextBoxに値をバインディングする際にValidation.ValidationAdornerSiteの設定も行います。
 Validation.ValidationAdornerSiteにはエラーメッセージを表示する要素をバインディングします。
 エラーメッセージを表示する側ではValidation.ValidationAdornerSiteForからエラーメッセージを取得します。
 これもややこしいですが定型文なので覚えるしかありません。

 どの方法を使用しても良いですが、個人的にはエラーテンプレートを指定する方法が一番わかりやすいかなと思います。
 次回はIDataErrorInfoを使用する場合のデータ検証について紹介します。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

カレンダー
08 | 2017/09 | 10
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
全記事表示リンク

全ての記事を表示する

カテゴリ
タグリスト

月別アーカイブ
09  08  07  06  05  04  03  02  01  12  11  10  09  08  07  06  04  03  02  01  12  11  10  09  08  07  06  05  04  03  02  01  12  11  10  09 
最新記事
リンク
最新コメント
検索フォーム
Amazon