C#のWPFでMVVMパターンを使用して日付の入力規則を設定する方法
C#のWPFでMVVMパターンを使用して日付の入力規則を設定する方法を紹介します。ここでは、日付の入力が正しい形式かどうか、特定の範囲内にあるかどうかをチェックする例を示します。### 手順#### 1. プロジェクトの作成と準備Visual Studioで新しいWPFアプリケーションプロジェクトを作成します。#### 2. ViewModelの作成日付の入力規則を含むViewModelを作成します。`INotifyDataErrorInfo`インターフェースを実装して、プロパティのエラーチェックを行います。```csharpusing System;using System.Collections;using System.Collections.Generic;using System.ComponentModel;using System.Globalization;using System.Runtime.CompilerServices;namespace WpfApp.ViewModels{ public class MainViewModel : INotifyPropertyChanged, INotifyDataErrorInfo { private DateTime? _dateOfBirth; private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>(); public DateTime? DateOfBirth { get => _dateOfBirth; set { _dateOfBirth = value; OnPropertyChanged(); ValidateDateOfBirth(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void ValidateDateOfBirth() { ClearErrors(nameof(DateOfBirth)); if (!DateOfBirth.HasValue) { AddError(nameof(DateOfBirth), "Date of birth cannot be empty."); } else if (DateOfBirth < new DateTime(1900, 1, 1) || DateOfBirth > DateTime.Today) { AddError(nameof(DateOfBirth), "Date of birth must be between 01/01/1900 and today."); } } #region INotifyDataErrorInfo public bool HasErrors => _errors.Count > 0; public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public IEnumerable GetErrors(string propertyName) { return _errors.ContainsKey(propertyName) ? _errors[propertyName] : null; } private void AddError(string propertyName, string error) { if (!_errors.ContainsKey(propertyName)) { _errors[propertyName] = new List<string>(); } if (!_errors[propertyName].Contains(error)) { _errors[propertyName].Add(error); OnErrorsChanged(propertyName); } } private void ClearErrors(string propertyName) { if (_errors.ContainsKey(propertyName)) { _errors.Remove(propertyName); OnErrorsChanged(propertyName); } } private void OnErrorsChanged(string propertyName) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } #endregion }}```#### 3. Viewの作成次に、XAMLファイルでViewを作成し、エラーメッセージを表示するためのスタイルとバインディングを設定します。```xml<Window x:Class="WpfApp.Views.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:vm="clr-namespace:WpfApp.ViewModels" mc:Ignorable="d" Title="MainWindow" Height="200" Width="400"> <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <Grid> <TextBox Text="{Binding DateOfBirth, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat=d}" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" VerticalAlignment="Top" Width="360"/> <TextBlock Text="{Binding (Validation.Errors).CurrentItem.ErrorContent, ElementName=dateOfBirthTextBox}" Foreground="Red" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/> </Grid></Window>```#### 4. エラースタイルの設定(オプション)エラーが発生した場合に、エラーのスタイルを設定することもできます。```xml<Window.Resources> <Style TargetType="TextBox"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="ToolTip" Value="{Binding (Validation.Errors).CurrentItem.ErrorContent, RelativeSource={RelativeSource Self}}" /> <Setter Property="BorderBrush" Value="Red" /> </Trigger> </Style.Triggers> </Style></Window.Resources>```### 完成したプロジェクト構造```WpfApp├── App.xaml├── App.xaml.cs├── ViewModels│ └── MainViewModel.cs├── Views│ └── MainWindow.xaml│ └── MainWindow.xaml.cs```### 実行結果アプリケーションを実行すると、`TextBox`に日付を入力できるようになります。### 実行結果アプリケーションを実行すると、`TextBox`に日付を入力できるようになります。日付が空である場合、または1900年1月1日より前、または今日より後の日付を入力した場合、エラーメッセージが表示されます。正しい日付が入力されると、エラーメッセージは消えます。### 追加の機能#### 1. DatePickerの使用WPFでは、日付の入力を簡単にするために`DatePicker`コントロールを使用することもできます。`DatePicker`を使用すると、ユーザーはカレンダーから日付を選択できるため、入力ミスが減ります。```xml<Window x:Class="WpfApp.Views.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:vm="clr-namespace:WpfApp.ViewModels" mc:Ignorable="d" Title="MainWindow" Height="200" Width="400"> <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <Grid> <DatePicker SelectedDate="{Binding DateOfBirth, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="360"/> <TextBlock Text="{Binding (Validation.Errors).CurrentItem.ErrorContent, ElementName=datePicker}" Foreground="Red" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/> </Grid></Window>```#### 2. カスタムバリデーションルールの作成`ValidationRule`クラスを継承してカスタムバリデーションルールを作成し、バインディングに適用することもできます。```csharpusing System;using System.Globalization;using System.Windows.Controls;public class DateValidationRule : ValidationRule{ public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if (value == null || string.IsNullOrWhiteSpace(value.ToString())) { return new ValidationResult(false, "Date of birth cannot be empty."); } if (DateTime.TryParse(value.ToString(), out DateTime date)) { if (date < new DateTime(1900, 1, 1) || date > DateTime.Today) { return new ValidationResult(false, "Date of birth must be between 01/01/1900 and today."); } return ValidationResult.ValidResult; } return new ValidationResult(false, "Invalid date format."); }}``````xml<Window x:Class="WpfApp.Views.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:vm="clr-namespace:WpfApp.ViewModels" xmlns:local="clr-namespace:WpfApp" mc:Ignorable="d" Title="MainWindow" Height="200" Width="400"> <Window.DataContext> <vm:MainViewModel /> </Window.DataContext> <Grid> <TextBox x:Name="dateOfBirthTextBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" VerticalAlignment="Top" Width="360"> <TextBox.Text> <Binding Path="DateOfBirth" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:DateValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <TextBlock Text="{Binding (Validation.Errors).CurrentItem.ErrorContent, ElementName=dateOfBirthTextBox}" Foreground="Red" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/> </Grid></Window>```### 完成したプロジェクト構造```WpfApp├── App.xaml├── App.xaml.cs├── ViewModels│ └── MainViewModel.cs├── Views│ └── MainWindow.xaml│ └── MainWindow.xaml.cs├── ValidationRules│ └── DateValidationRule.cs```### まとめこのサンプルでは、WPFでMVVMパターンを使用して日付の入力規則を設定する方法を示しました。`INotifyDataErrorInfo`インターフェースを使用してプロパティの検証を行い、`DatePicker`コントロールやカスタムバリデーションルールを使用することで、ユーザーが正しい形式の日付を入力するよう支援します。このアプローチを使用することで、他の入力フィールドに対しても同様に検証ロジックを追加できます。