Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

ReactiveProperty v1.2.0をリリースしました

$
0
0

先日書いた記事で、めんどくさいと思ってた部分を簡単にかけるようにしました。

MVVMでめんどくさいと思ってる部分を、個人的にどうやって緩和してるか - かずきのBlog@hatena

データのバリデーションンを伴うMとVMのプロパティの同期は以下のように書く必要がありました。

publicclass PersonViewModel
{
    public ReactiveProperty<string> Name { get; private set; }

    public ReactiveProperty<string> Age { get; private set; }

    public PersonViewModel(Person model)
    {
        this.Name = model                                                    // M -> VM
            .ObserveProperty(x => x.Name)                                    // IObservable<string>に変換して
            .ToReactiveProperty()                                            // ReactiveProperty<string>に変換して
            .SetValidateNotifyError(x =>                                     // 空文字の時はエラーにするstring.IsNullOrWhiteSpace(x) ? "Name is required" : null);
        this.Name                                                            // VM -> M
            .Where(_ => !this.Name.HasErrors)                                // エラーが無いときは
            .Subscribe(x => model.Name = x);                                 // 値を書き戻すthis.Age = model                                                     // M -> VM
            .ObserveProperty(x => x.Age)                                     // IObservable<int>に変換して
            .Select(x => x.ToString())                                       // IObservable<string>に変換して
            .ToReactiveProperty()                                            // ReactiveProperty<string>に変換して
            .SetValidateNotifyError(x =>                                     // int型に変換できない場合はエラーにする
            {
                int result; // no usereturnint.TryParse(x, out result) ? null : "";
            });
        this.Age                                                             // VM -> M
            .Where(_ => !this.Age.HasErrors)                                 // エラーが無いときは
            .Select(x => int.Parse(x))                                       // int型に変換して
            .Subscribe(x => model.Age = x);                                  // 書き戻す
    } 
}

これを、ToReactivePropertyAsSynchronizedメソッドにバリデーションエラーのときは値を無視するようにするオプションを追加して以下のようにかけるようにしました。

publicclass PersonViewModel
{
    public ReactiveProperty<string> Name { get; private set; }

    public ReactiveProperty<string> Age { get; private set; }

    public PersonViewModel(Person model)
    {
        this.Name = model
            .ToReactivePropertyAsSynchronized(
                x => x.Name,
                ignoreValidationErrorValue:true)
            .SetValidateNotifyError(x => string.IsNullOrEmpty(x) ? "error": null);
         
        this.Age = model                                                    
            .ToReactivePropertyAsSynchronized(
                x => x.Age,
                convert: x => x.ToString(),
                convertBack: x => int.Parse(x),
                ignoreValidationErrorValue:true)
            .SetValidateNotifyError(x =>
                {
                    int result; // no usereturnint.TryParse(x, out result) ? null : "error";
                });
    } 
}

今まではバリデーションエラーが、あろうが無かろうが、Mへ値が渡されてたのですが(しかも、convertBackに変な値がわたって例外がでると死ぬ)バリデーションエラーのときは値を流さないようにしました。個人的に気に入ってる。

動作は以下のようになります。

var model = new Person { Name = "tanaka", Age = 30 };
var vm = new PersonViewModel(model);

Console.WriteLine("{0} {1}", model.Name, model.Age); // tanaka 30

vm.Age.Value = "50"; // valid value
Console.WriteLine("{0} {1}", model.Name, model.Age); // tanaka 50

vm.Age.Value = "XX"; // invalid value
Console.WriteLine("{0} {1}", model.Name, model.Age); // tanaka 50

vm.Age.Value = "30"; // valid value
Console.WriteLine("{0} {1}", model.Name, model.Age); // tanaka 30

Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>