ReactiveProperty同士で双方向バインディングする

#はじめに
ReactiveProperty同士で双方向バインディングしたい状況があり、その方法について調査したのですが記述している情報がネット上でないっぽいので紹介がてら投稿します。

#状況
![a.png](https://qiita-image-store.s3.amazonaws.com/0/109302/9ad008fa-9167-6394-cdbf-d3d0d4e74312.png)
こんな感じでViewModelではプリミティブっぽい型で入力を受けて、正しい情報はModelで保持。その際にはDDD的なValueObjectに変換済みにしておきたい状況です。
ちなみにModelが[INotifyPropertyChanged][]を継承している場合の[ToReactivePropertyAsSynchronized][]を使用した双方向バインディングの例は多数ありました。

Inputに入力するべき初期値がViewModelのコンストラクタ時点で入手可能ならばViewModel -> ModelのOneWay的なバインディングでも良かったんですが、今回の状況としては初期値は非同期処理の後で手に入るため、Model -> ViewModelのOneWayToSource的なバインディングもしたかったです。

#サンプルとライブラリ

- [ReactivePropertySample(自作)][]
    - ReactiveProperty: 5.3.2
    - prism: 7.1.0.431

- [ReactiveProperty(ライブラリ)](https://github.com/runceel/ReactiveProperty)

#実装例
実際に動作するソースは[ReactivePropertySample(自作)][]を参照。

```C#:Model
    public class Model
    {
        public ReactivePropertySlim<ValueObject> VO { get; } = new ReactivePropertySlim<ValueObject>();

        public async void 非同期処理Async()
        {
            var ret = await なんか非同期処理();
            VO.Value = new ValueObject(ret.非同期処理で手に入れた初期値);
        }
    }
```

```C#:ViewModel
    public class ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private CompositeDisposable DisposeCollection = new CompositeDisposable();
        public ReactiveProperty<string> Input { get; }
        public Model Model { get; }

        public ViewModel(Model _model)
        {
                Model = _model;
                Input =
                    Model.VO.ToReactivePropertyAsSynchronized(
                        x => x.Value, // propertySelector.
                        x => x.Name/* ValueObject型のstirngプロパティ */,  // convert.
                        x => new ValueObject(x), // convertBack.
                        ReactivePropertyMode.Default | ReactivePropertyMode.IgnoreInitialValidationError, // mode.
                        true // ignoreValidationErrorValue.
                    ).SetValidateNotifyError(x => String.IsNullOrEmpty(x) ? "何か入力してください。" : null) // バリデーション.
                    .AddTo(DisposeCollection);
        }

        public void OnNavigatedTo(NavigationContext navigationContext) => Model.非同期処理Async();
    }
```

#解説
結局[ToReactivePropertyAsSynchronized][]を使用して実現するんですけど。
言いたいことは[ToReactivePropertyAsSynchronized][]は[INotifyPropertyChanged][]を型パラメーターの制約に指定しているので[INotifyPropertyChanged][]を継承している[ReactiveProperty(Slim)](https://github.com/runceel/ReactiveProperty/blob/37417c704c011abcfd6eedf9e8ced8f708916e9a/Source/ReactiveProperty.NETStandard/IReactiveProperty.cs)でも使用できますよってことです。

#まとめ
メソッドの使い方の一例として誰かの参考になればと思います。


[ReactivePropertySample(自作)]:https://github.com/kwhrkzk/ReactivePropertySample/tree/master/ReactivePropertySample/ViewModule/ToReactivePropertyAsSynchronized    
[ToReactivePropertyAsSynchronized]:https://github.com/runceel/ReactiveProperty/blob/37417c704c011abcfd6eedf9e8ced8f708916e9a/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs
[INotifyPropertyChanged]:https://docs.microsoft.com/ja-jp/dotnet/api/system.componentmodel.inotifypropertychanged?view=netframework-4.7.2