かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

PrismとReactivePropertyのつなぎ その3

ちまちまとした拡張メソッドだけではなく、こんな感じでIInteractionRequestを実装したクラスを作ってしまうのもありかも??まだ、スケジューラとかについては何も考えてないけど、とりあえずのやっつけで・・・。

namespace Okazuki.KinkumaFramework.ReactiveProperty
{
    using System;
    using System.Reactive.Linq;
    using System.Reactive.Subjects;
    using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
    using System.Reactive.Disposables;

    public static class InteractionRequestExtensions
    {
        public static ReactiveInteractionRequest<T> ToReactiveInteractionRequest<T>(this IObservable<T> self)
            where T : Notification
        {
            return new ReactiveInteractionRequest<T>(self);
        }
    }

    public class ReactiveInteractionRequest<T> : IInteractionRequest, IObservable<T>, IDisposable
        where T : Notification
    {
        private SingleAssignmentDisposable disposable = new SingleAssignmentDisposable();

        private Subject<T> subject = new Subject<T>();

        public ReactiveInteractionRequest(IObservable<T> o)
        {
            this.disposable.Disposable = o.Subscribe(n =>
            {
                this.OnRaised(n);
            });
        }

        public ReactiveInteractionRequest() : this(Observable.Never<T>())
        {
        }

        public event EventHandler<InteractionRequestedEventArgs> Raised;

        private void OnRaised(T t)
        {
            var h = this.Raised;
            if (h != null)
            {
                h(this, new InteractionRequestedEventArgs(t, () =>
                {
                    subject.OnNext(t);
                }));
            }
        }

        public IObservable<T> Raise(T n)
        {
            this.OnRaised(n);
            return this.AsObservable();
        }

        public IDisposable Subscribe(IObserver<T> observer)
        {
            return this.subject.Subscribe(observer);
        }

        public void Dispose()
        {
            if (this.disposable.IsDisposed)
            {
                return;
            }

            this.subject.OnCompleted();
            this.disposable.Dispose();
        }
    }

}

こうすると、IObservableからReactiveInteractionRequestになるしReactiveInteractionRequestから各種ReactivePropertyの便利クラスとつながるかも??因みに、その1とその2で書いたコードと今回のコードを使った場合の比較のため並べてみます。

// 普通
this.EditCommand
    .Subscribe(_ =>
    {
        var vm = new EditWindowViewModel(this.SelectedItem.Value);
        this.ShowEditWindowRequest.Raise(
            new Notification
            {
                Title = vm.EditTargetViewModel.Value.Name.Value + " Editing",
                Content = vm
            },
            n =>
            {
                // ここにいろいろ処理をかく
            });
    });
// 前回のコード
this.EditCommand
    // InteractionRequest経由で編集画面を表示
    .SelectMany(_ =>
        // ShowEditWindowRequestはInteractionRequest<Notification>型のプロパティ
        // XAML側でウィンドウを表示するTriggerActionと紐づけてるイメージ
        this.ShowEditWindowRequest.RaiseAsObservable(
            new Notification
            {
                Title = vm.EditTargetViewModel.Value.Name.Value + " Editing",
                Content = new EditWindowViewModel(this.SelectedItem.Value)
            }))
    .Subscribe(n =>
    {
        var vm = n.Content as EditWindowViewModel;
        // 結果を受けて何なりと処理をやる
        // 主にModelへの委譲
    });
// 今回の場合
this.ShowEditWindowRequest = this
    .EditCommand
    .Select(_ => new Notification
    {
        Title = "編集",
        Content = new EditWindowViewModel(this.SelectedItem.Value)
    })
    .ToReactiveInteractionRequest();
this.ShowEditWindowRequest.Subscribe(n =>
{
    var vm = n.Content as EditWindowViewModel;
    // ここにいろいろな処理を書く
});

それっぽくなってきたかもしれん?