前に汎用性の欠片も無い感じに実装して実験したINotifyDataErrorInfoですが、System.ComponentModel.DataAnnotationsと連携させる感じで汎用的に実装できます。
とりあえず、INotifyDataErrorInfoとINotifyPropertyChangedを実装したViewModelBaseクラスは、こんな雰囲気になると思います。
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; namespace SilverlightApplication19 { public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo { public event PropertyChangedEventHandler PropertyChanged; public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public System.Collections.IEnumerable GetErrors(string propertyName) { var result = new List<ValidationResult>(); // TryValidatePropertyが適任。プロパティの値を取得するのにリフレクションを // 使っている部分が気に入らない if (Validator.TryValidateProperty( GetType().GetProperty(propertyName).GetValue(this, null), new ValidationContext(this, null, null) { MemberName = propertyName }, result)) { return null; } return result.Select(vr => vr.ErrorMessage); } // PropertyChangedとErrorChangedイベントを発行する protected virtual void OnPropertyChanged(string propertyName) { RaisePropertyChanged(propertyName); RaiseErrorChanged(propertyName); // HasErrorsプロパティにも変更があったことを通知する RaisePropertyChanged("HasErrors"); } private void RaisePropertyChanged(string propertyName) { var h = PropertyChanged; if (h == null) return; h(this, new PropertyChangedEventArgs(propertyName)); } private void RaiseErrorChanged(string propertyName) { var h = ErrorsChanged; if (h == null) return; h(this, new DataErrorsChangedEventArgs(propertyName)); } // オブジェクトにエラーがあったらtrue返す public bool HasErrors { get { var dummy = new List<ValidationResult>(); // TryValidateObjectが適任 return !Validator.TryValidateObject( this, new ValidationContext(this, null, null), dummy); } } } }
これを使う側では、普通にプロパティを定義して、DataAnnotationsにある属性をつけるだけです。
using System.ComponentModel.DataAnnotations; namespace SilverlightApplication19 { public class PersonViewModel : ViewModelBase { private string _fullName; [Required(ErrorMessage="名前を入力してください")] public string FullName { get { return _fullName; } set { _fullName = value; OnPropertyChanged("FullName"); } } } }
適当に、このPersonViewModelを表示する画面を作って動きを確認します。
<UserControl x:Class="SilverlightApplication19.MainPage" 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" xmlns:local="clr-namespace:SilverlightApplication19" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.DataContext> <local:PersonViewModel FullName="田中 太郎" /> </UserControl.DataContext> <Grid x:Name="LayoutRoot" Background="White"> <TextBlock HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBlock1" Text="FullName" VerticalAlignment="Top" /> <TextBox Text="{Binding Path=FullName, Mode=TwoWay}" Height="24" HorizontalAlignment="Left" Margin="72,8,0,0" Name="textBox1" VerticalAlignment="Top" Width="148" /> <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,38,0,0" Name="button1" VerticalAlignment="Top" Width="75" /> </Grid> </UserControl>
必須入力にしてるので、テキストボックスを空っぽにするとエラーが表示されます。
いい感じかも。