見出し画像

INotifyPropertyChangedの実装(WPF C#) - 開発備忘録3 -

こんばんは。市場価値0です。

今回は、WPFの基本である、INotifyPropertyChangedの実装について記載します。

筆者はWPFが大好きです。力技が効くので。

実際の開発プロジェクトにおいて、本当にイチからWPFアプリを作らない限りは、INotifyPropertyChangedの実装を意識することってあんまりないのではないかと思います(既に親クラスで実装されている等)

何か学びになれば良いなと思いやってみました。

Microsoft Learnに今回の実装内容とまんま同じことが書いてあるので、完全に「やってみた」だけの記事になります。

前提① WPFとは

WPFとは

解像度に依存せず、ベクターベースのレンダリング エンジンを使用し、最新のグラフィックス ハードウェアを活用するために構築された UI フレームワークです。 WPF では、Extensible Application Markup Language (XAML)、コントロール、データ バインディング、レイアウト、2D および 3D グラフィックス、アニメーション、スタイル、テンプレート、ドキュメント、メディア、テキスト、タイポグラフィなどの、アプリケーション開発機能の包括的なセットが提供されます。

https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/overview/?view=netdesktop-8.0

Microsoftが提供している、GUI開発のための技術です。

エロゲみたいに「hoge.exe」を実行するとGUIが起動するようなアプリを作ることができます。

MVVMと呼ばれるパターンに従って実装することで、画面と内部処理の実装を分離することができるのが強みです。(次で詳述します)

WPFの基本的な実装

先述した、MVVMというパターンに従って、実装を行います。

MVVMとは、プログラムをModel - View - ViewModelという3つの構成要素に分ける実装パターンです。
それぞれの構成要素は、以下の役割を持ちます。

・Model
 ViewModelを通じて渡された画面表示内容の加工や、ボタンクリック等の
 イベントが発生した際の内部処理を定義します。

・View
 画面に表示されるコントロール(ボタンとか)やレイアウトを定義します。

・ViewModel
 ModelとViewの仲介役です。Viewで発生したイベントをModelへ渡したり、
 Modelで行った処理の結果をViewへ渡す役割を持ちます。

前提② INotifyPropertyChangedとは

バインディング ターゲットのプロパティにバインディング ソースの動的変更が自動的に反映される (たとえば、ユーザーがフォームを編集するとプレビュー ペインが自動的に更新される) ようにするために、OneWay または TwoWay バインディングをサポートするには、クラスが適切なプロパティ変更通知を提供する必要があります。

https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/data/how-to-implement-property-change-notification?view=netframeworkdesktop-4.8

画面上、または内部処理上での変更をお互いに通知し、反映させるために必要な実装になります。

やってみた

実際にやってみます。
今回はサンプルプログラムとして、ボタンを押すとトリコの釘パンチ連数をランダムに生成するアプリを作成してみました。

画面の初期状態はこんな感じです。

0練釘パンチ

釘パンチ乱数生成ボタンを押すと、ボタン下のテキストボックスの内容が変化します。

664400300連釘パンチ

グルメ界突入編前くらいのインフレの中で放たれる釘パンチ連数を生成することができました。

それでは以下に、ViewとViewModelの実装を記載します。

View

<Button HorizontalAlignment="Center" VerticalAlignment="Center"
        Content="釘パンチ乱数生成" FontSize="20px"
        Padding="10px" Margin="10px"
        Click="Button_Click"/>
<TextBox Text="{Binding Count, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, StringFormat={}{0}連釘パンチ}"
        BorderBrush="Black" TextAlignment="Center"
        FontSize="20px" Padding="10px" Margin="10px"
        IsEnabled="False"/>

ボタンとテキストボックスの箇所のみ、抜き出しました。
ボタンの Click="Button_Click" の箇所では、ボタンが押下された際にViewModelから呼び出されるイベントハンドラーを定義しています。

テキストボックス内では、Text="{Binding … の部分でViewModel側で定義したプロパティとテキストボックス内でのテキストの紐付けをおこなっています。

ViewModel

namespace WpfApp1
{
    public class ViewModel : ViewModelBase
    {
        private int _Count;

        public int Count
        {
            get { return _Count; }
            set
            {
                if (_Count != value)
                {
                    _Count = value;
                    OnPropertyChanged();
                }
            }
        }

        public void RandomButtonClick()
        {
            var random = new Random();
            this.Count = random.Next(0, int.MaxValue);
        }
    }
}

今回の肝であるINotifyPropertyChangedはViewModelの親クラスとしてViewModelBaseを作成し、その中で実装しました。

テキストボックスの文字と紐付けたCountプロパティの内容が変更された際に、親クラスで定義したOnPropertyChangedプロパティを呼び出すことで、変更通知を行なっています。

RandomButtonClickメソッドは、ボタン押下時に実行される処理です。
Intの最大値までトリコの釘パンチ連数をランダムで生成します。

ViewModelBase

namespace WpfApp1
{    
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

INotifyPropertyChangedを継承した親クラスとしてViewModelBaseを実装しました。

ViewModelに直接書いてしまうと、別のViewModelを作成した際に同じことを記述しなければならないので、INotifyPropertyChangedイベントを実装した親クラスを個別のViewModelで継承するのが良いかと思います。

結び

なんかやってみただけになってしまったので、次回もWPFの変更通知について掘り下げてみたいと思います。



この記事が気に入ったらサポートをしてみませんか?