WPF_Prism_ErrorsContainer

ErrorsContainerについて

ErrorsContainerとは

ErrorsContainerは、INotifyDataErrorInfoの実装ヘルパークラスです。

INotifyDataErrorInfo実装時に、発生中のエラー情報を保持するためにDictionary型のメンバを用意してましたが、管理が煩雑だという問題がありました。

そこで、発生中のエラー情報を簡単に扱えるようにするためのクラスがErrorsContainerです。


実装について

ErrorsContainerでは、下記処理を各ViewModelにそれぞれ追加することになります。

  1. ErrorsContainerのフィールド作成する。
  2. ErrorsContainerを使ってINotifyDataErrorInfoの実装する。
  3. 入力値検証用のメソッド作成する。
  4. プロパティに入力値検証のための実装を行う。

ErrorsContainer実装例

System.ComponentModel.DataAnnotationsの参照が必要です。


using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;

namespace WpfPrismMvvm
{
    public class MainWindowViewModel : BindableBase, INotifyDataErrorInfo
    {
        private string _firstname;
        [Required(ErrorMessage = "名前の入力は必須です。")]
        public string FirstName
        {
            get { return this._firstname; }
            set
            {
                this.SetProperty(ref this._firstname, value);
                this.ValidateProperty(value);
            }
        }

        private string _lastname;
        [Required(ErrorMessage = "性の入力は必須です。")]
        public string LastName
        {
            get { return this._lastname; }
            set
            {
                this.SetProperty(ref this._lastname, value);
                this.ValidateProperty(value);
            }
        }

        public MainWindowViewModel()
        {
            _errorsContainer = new ErrorsContainer<string>(OnErrorsChanged);
            this.FirstName = string.Empty;
            this.LastName = string.Empty;
        }

        /// <summary>
        /// 入力値の検証を行う。
        /// </summary>
        /// <memo>System.ComponentModel.DataAnnotationsの参照を追加すること</memo>
        /// <param name="value">入力値</param>
        /// <param name="propertyName">プロパティ名</param>
        protected void ValidateProperty(object value, [CallerMemberName]string propertyName = null)
        {
            var context = new ValidationContext(this) { MemberName = propertyName };
            var validationErrors = new List<ValidationResult>();
            if (!Validator.TryValidateProperty(value, context, validationErrors))
            {
                var errors = validationErrors.Select(error => error.ErrorMessage);
                this._errorsContainer.SetErrors(propertyName, errors);
            }
            else
            {
                this._errorsContainer.ClearErrors(propertyName);
            }
        }

        #region INotifyDataErrorInfoの実装
        /// <summary>
        /// 保持したいエラー情報の型を指定して、ErrorsContainerのフィールドを作成する。
        /// </summary>
        private ErrorsContainer<string> _errorsContainer;

        /// <summary>
        /// エラーに変更があったときに通知される。
        /// </summary>
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        /// <summary>
        /// 指定したプロパティのエラー情報を取得する。
        /// </summary>
        /// <param name="propertyName">プロパティ名</param>
        /// <returns>エラー情報</returns>
        public System.Collections.IEnumerable GetErrors(string propertyName)
        {
            return _errorsContainer.GetErrors(propertyName);
        }

        /// <summary>
        /// 指定したプロパティ名のエラーに変更があったことを通知する。
        /// <param name="propertyName">プロパティ名</param>
        /// </summary>
        private void OnErrorsChanged([CallerMemberName] string propertyName = null)
        {
            var handler = this.ErrorsChanged;
            if (handler != null)
            {
                handler(this, new DataErrorsChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// エラーがある場合trueを返す。
        /// </summary>
        public bool HasErrors
        {
            get
            {
                return _errorsContainer.HasErrors;
            }
        }
        #endregion
    }
}

xaml

Validation.ErrorTemplateを設定します。


<Window x:Class="WpfPrismMvvm.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <ControlTemplate x:Key="ValidationTemplate">
            <StackPanel>
                <TextBlock Foreground="Red" Text="{Binding AdornedElement.(Validation.Errors)[0].ErrorContent, ElementName=adornedelem}" />
                <AdornedElementPlaceholder x:Name="adornedelem" />
            </StackPanel>
        </ControlTemplate>
    </Window.Resources>
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="FirstName: " Margin="5,20,5,5" />
            <TextBox Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}"
                 MinWidth="200" Height="20" Margin="5,20,5,5" HorizontalAlignment="Left" TextWrapping="Wrap"
                 Validation.ErrorTemplate="{StaticResource ValidationTemplate}" />
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="LastName: " Margin="5,20,5,5" />
            <TextBox Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}"
                 MinWidth="200" Height="20" Margin="5,20,5,5" HorizontalAlignment="Left" TextWrapping="Wrap"
                 Validation.ErrorTemplate="{StaticResource ValidationTemplate}" />
        </StackPanel>
    </StackPanel>
</Window>


関連ページ