かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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;
    // ここにいろいろな処理を書く
});

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