「東雲 忠太郎」の平凡な日常のできごと

「東雲 忠太郎」の平凡な日常のできごと

2024.08.14
XML
カテゴリ: WPFC#.NET


`INotifyDataErrorInfo` を使用して、1つのプロパティに対して複数のエラーメッセージを返す WPF アプリケーションのサンプルコードを以下に示します。このサンプルでは、`Name` と `Age` のバリデーションを行い、エラーが発生した場合に複数のエラーメッセージを返します。


### **1. Model クラス (`Person`)**


```csharp

using System.Collections;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;


namespace WpfAppValidationExample

{

    public class Person : INotifyPropertyChanged, INotifyDataErrorInfo

    {

        private string _name;

        private int _age;

        private readonly Dictionary<string, List<string>> _errors = new Dictionary<string, List<string>>();


        public string Name

        {

            get => _name;

            set

            {

                _name = value;

                OnPropertyChanged(nameof(Name));

                ValidateName();

            }

        }


        public int Age

        {

            get => _age;

            set

            {

                _age = value;

                OnPropertyChanged(nameof(Age));

                ValidateAge();

            }

        }


        public event PropertyChangedEventHandler PropertyChanged;

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;


        public bool HasErrors => _errors.Any();


        public IEnumerable GetErrors(string propertyName)

        {

            if (string.IsNullOrEmpty(propertyName))

                return _errors.Values.SelectMany(e => e);


            return _errors.ContainsKey(propertyName) ? _errors[propertyName] : null;

        }


        protected void OnPropertyChanged(string propertyName)

        {

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        }


        private void ValidateName()

        {

            ClearErrors(nameof(Name));


            if (string.IsNullOrWhiteSpace(Name))

            {

                AddError(nameof(Name), "Name is required.");

            }

            if (Name != null && Name.Length < 2)

            {

                AddError(nameof(Name), "Name must be at least 2 characters long.");

            }

            if (Name != null && !Name.All(char.IsLetter))

            {

                AddError(nameof(Name), "Name must contain only letters.");

            }

        }


        private void ValidateAge()

        {

            ClearErrors(nameof(Age));


            if (Age <= 0 || Age > 120)

            {

                AddError(nameof(Age), "Age must be between 1 and 120.");

            }

            if (Age < 18)

            {

                AddError(nameof(Age), "Age must be at least 18.");

            }

        }


        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);

                ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));

            }

        }


        private void ClearErrors(string propertyName)

        {

            if (_errors.ContainsKey(propertyName))

            {

                _errors.Remove(propertyName);

                ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));

            }

        }

    }

}

```


### **2. ViewModel クラス (`MainViewModel`)**


```csharp

using System.ComponentModel;


namespace WpfAppValidationExample

{

    public class MainViewModel : INotifyPropertyChanged

    {

        private Person _person;


        public MainViewModel()

        {

            _person = new Person();

        }


        public Person Person

        {

            get => _person;

            set

            {

                _person = value;

                OnPropertyChanged(nameof(Person));

            }

        }


        public event PropertyChangedEventHandler PropertyChanged;


        protected void OnPropertyChanged(string propertyName)

        {

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        }

    }

}

```


### **3. View (XAML)**


```xml

<Window x:Class="WpfAppValidationExample.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="Input Validation Example" Height="250" Width="400">

    <Window.DataContext>

        <local:MainViewModel />

    </Window.DataContext>

    <Grid Margin="20">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="Auto"/>

        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Margin="0 0 0 10">

            <TextBlock Text="Name:" />

            <TextBox Text="{Binding Person.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />

        </StackPanel>

        <StackPanel Grid.Row="1" Margin="0 0 0 10">

            <TextBlock Text="Age:" />

            <TextBox Text="{Binding Person.Age, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />

        </StackPanel>

        <Button Content="Submit" Grid.Row="2" Width="100" Height="30" />

        <TextBlock Grid.Row="3" Foreground="Red" Margin="0 10 0 0">

            <ItemsControl ItemsSource="{Binding Person.(Validation.Errors)}">

                <ItemsControl.ItemTemplate>

                    <DataTemplate>

                        <TextBlock Text="{Binding ErrorContent}" />

                    </DataTemplate>

                </ItemsControl.ItemTemplate>

            </ItemsControl>

        </TextBlock>

    </Grid>

</Window>

```


### **4. MainWindow.xaml.cs**


```csharp

using System.Windows;


namespace WpfAppValidationExample

{

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

        }

    }

}

```


### **5. プロジェクトのセットアップ**

- 上記の `Person` クラス、`MainViewModel` クラス、および `MainWindow.xaml` ファイルをプロジェクトに追加します。

- `MainWindow.xaml.cs` も同様にセットアップします。


### **動作確認**

このサンプルでは、以下のバリデーションが行われます。


- **Name**

  - 空白または `null` の場合: 「Name is required.」

  - 2文字未満の場合: 「Name must be at least 2 characters long.」

  - 文字以外が含まれている場合: 「Name must contain only letters.」


- **Age**

  - 1 未満または 120 を超える場合: 「Age must be between 1 and 120.」

  - 18未満の場合: 「Age must be at least 18.」


エラーが発生した場合、`TextBox` の下にエラーメッセージが表示されます。複数のエラーメッセージがある場合、すべて表示されます。


### **まとめ**

このサンプルでは `INotifyDataErrorInfo` を用いて、1つのプロパティに対して複数のエラーメッセージを返す方法を示しました。これにより、複雑なバリデーション要件を持つアプリケーションに対応することができます。






お気に入りの記事を「いいね!」で応援しよう

Last updated  2024.08.14 14:47:35


【毎日開催】
15記事にいいね!で1ポイント
10秒滞在
いいね! -- / --
おめでとうございます!
ミッションを達成しました。
※「ポイントを獲得する」ボタンを押すと広告が表示されます。
x
X

© Rakuten Group, Inc.
X
Mobilize your Site
スマートフォン版を閲覧 | PC版を閲覧
Share by: