WPF_Prism_ErrorsContainer



ErrorsContainerについて

ErrorsContainerとは

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

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

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


実装について

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

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

コード量が増えるため、BindableBaseとINotifyDataErrorInfoを継承した抽象基底クラスを自身で実装したほうが良いかもしれません。


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>


関連ページ



スポンサード リンク