11.PrismでReactiveProperty(model編)

こんにちは、ゆたんぽです。

本日は前回に引き続きReactiveRropertyを説明していきます。

前回は、①のView⇔ViewModelでの連携を行いました。

今回は②ViewModel⇔Modelへの通知を行う方法を説明していきます。

私は②ViewModel⇔Modelへの通知 がとても苦労したので、有益な情報になると思います。


Model側への通知準備

Model側へ通知するための準備を行います。

まずは、ソリューションを右クリックして、NuGetの管理を開いてください。

参照タブで、「Fody」と検索してください。

すると「PropertyChanged.Fody」が見つかると思いますので、上記のように選択してインストールを行ってください。現時点でバージョンは「v3.4.0」が最新です。

インストールをクリックすると「同意画面」が出てくるので同意してください。


実装

それでは、実際に実装を始めます。前回の記事で作成したプロジェクトをそのまま使用しますので、途中から見た方は前回の記事を確認して下さい。

今回は、「View側のInputで入力した数値に対して、Model側で10を掛け算して、Outputへ返す」という簡単なプログラムを実装していきます。

上記を達成するために「ViewModel⇔Model」の通知を行う必要があります。

Modelの作成

まず、下のようにModelを格納するフォルダを作成します。

上記のように「ReactiveTest」を右クリックして、「追加」→「新しいフォルダー」で新しいフォルダーを作成します。
名前は上記のように「Models」としてください。
次に作成した「Models」のフォルダーを右クリックして、上記のように「追加」→「新しい項目」を選択してください。
そこで「クラス」を選択して、「Calc」というクラスを作成します。

Modelの実装

作成した「Calc.cs」クラスを実装していきます。

using PropertyChanged;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace ReactiveTest.Models
{
    [AddINotifyPropertyChangedInterface]//①

    public class Calc : INotifyPropertyChanged//②
    {
        public event PropertyChangedEventHandler PropertyChanged;//③

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)//④
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        public string Input { get; set; }//⑤

        public string Output { get; set; }//⑥

        public void Multi()//⑦
        {
            var input = Convert.ToDouble(Input);

            var output = input * 10;

            Output = output.ToString();
        }
    }
}

①[AddINotifyPropertyChangedInterface]を実装します。実装後、[Ctrl + .]などで「using PropertyChanged」を追加して、使用できるようにします。ここで、先ほどインストールした「Fody」を使用することを宣言しています。

②INotifyPropertyChangedを継承します。後ほどViewModel側でViewModel⇔Viewを関連付ける処理を行うのですが、Model側にINotifyPropertyChanged を継承しないと関連付けの処理ができなくなりますので忘れずに記入しましょう。

③値が変更される「PropertyChanged」のイベントを宣言しています。

④「RaisePropertyChanged」を実装しています。ここで、Model→ViewModelの通知を行っています。

詳細まで、私も理解していませんが、①~④はおまじないのようにModel側に実装するとViewModel⇔Model側の連携が取れるようになります。

⑤Inputの値を受け取るようにしています。ViewModelで参照できるようにpublicにしてください。

⑥⑤同様にOutputも定義します。

⑦ここでは実際の処理を記入しています。Stringで受けたInputの値を10倍して、String型に戻してOutputへ格納しています。

ViewModelの編集

using Prism.Mvvm;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using ReactiveTest.Models;
using System.Reactive.Disposables;
using System;

namespace ReactiveTest.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        // リアクティブプロパティ破棄
        protected CompositeDisposable _disposables = new CompositeDisposable();//①

        private string _title = "Prism Application";

        Calc calcTest; //②

        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        public ReactiveProperty<string> Input { get; }

        public ReactiveProperty<string> Output { get; }

        public MainWindowViewModel()
        {
            calcTest = new Calc();//③

            Input = calcTest.ToReactivePropertyAsSynchronized(x => x.Input)//④
                .AddTo(_disposables);

            Input.Subscribe(_=> calcTest.Multi());//⑤

            Output = calcTest.ToReactivePropertyAsSynchronized(x => x.Output)//⑥
                .AddTo(_disposables);

        }
    }
}

①後ほど実装する、リアクティブプロパティを破棄するための「Dispose」処理を定義しています。使用するために「using System.Reactive.Disposables;」が必要です。

②先ほど作成した「Calc.cs」を宣言しています。使用するために「using ReactiveTest.Models;」が必要です。

③コンストラクタで②の内容をインスタンス化しています。

④ここで、ViewModel側の「Input」とModel側の「Input」を紐づけています。先ほどインスタンス化した「calctest」をToReactivePropertyAsSynchronizedで「x => x.Input」を呼び出して、Inputと紐づけしています。
この処理を行うと「ViewModel⇔Model」への連携ができます。しかし、Model側で「INotifyPropertyChanged」を実装していないと、エラーが起きるので事前に実装しておきましょう。

また、「.AddTo(_disposables)」でDipose処理を行って、メモリーリークを起こさないようにしています。

⑤SubScribeの処理を行って、Inputの値が変更されたときの処理を記述しています。ここでは、calcTestのCalc処理を行ってInputの値に10をかけてOutputに格納しています。

⑥④のInput同様に 「ViewModel⇔Model」への連携 を行っています。

ここまで来たら起動してみましょう。

上記のように入力した値に対して、値が変わるたびに10倍された値が表示されたら成功です。

この処理は、Viewから入力された値がデータバインディングによって、ViewModelへ通知されて、ViewModelで変更された値がModel側に通知、処理され、ViewModelを経てView側へOutput値の通知が成功していることがわかります。

よって、View⇔ViewModel⇔Modelの連携が取れたことが確認できました。


まとめ&次回予告

今回は ReactiveRropertyを使用して、ViewModel⇔Modelへの連携を説明していきました。

前回の内容と、今回の内容を使用することで、View⇔ViewModel⇔Modelの連携が取れるようになります。

是非、利用してみてください。

私も理解が不足してあるところがありますので、今後理解したらより詳細を追記していこうと思います。

次回は、ReactiveRropertyのほかの機能を説明していこうと思いますので、よろしくお願いします。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です