2017-02-23 4 views
2

私は現在、アプリケーション用のウィザードシステムを構築していますが、ReactiveUIを使用しており、結果としてRxです。Reactive Extensionsネストされた階層のアンフォールド/スキャンアプローチ

ウィザードの各ステップは、IWizardStep<T>を実装しています。ここで、Tは、最終的にウィザードが生成するデータ型にすぎません。

各ステップには、データ入力に基づいて分岐を可能にするために、ユーザーが次のステップに移動するためのステップが必要です。

ステップは、同様の構造を有すると考えることができる。IStepChoice<T>

public interface IWizardStep<T> 
{ 
    IObservable<IStepChoice<T>> NextStepChoice {get;} 
} 

単にある:

public interface IStepChoice<T> 
{ 
    IWizardStep<T> Step {get;} 
    string Reason {get;} 
} 

開始から終了までの電流経路を計算するために、のためにユーザーに表示するには、私は開始ステップから行くことができ、NextStepChoiceチェーンに沿って再帰的にそれがnullに達するまで歩く必要があります(それはNextStepChoiceのために有効な動作です。彼はウィザード)。

私はObservable.Scanを見ましたが、私の人生のために、これを正しく再帰的に動作させる方法を考え出すことはできません。

また、これは古典的な展開型の問題であるため、有望に見えるObservable.Generateを見ました。唯一の問題は、Generateがループを中断するタイミングを決定する関数をとることですが、これを実行するには内部観測可能性を評価する必要があります。

Observable.Generate(
    new WizardStepChoice<T>(start, null), 
    choice => choice != null, 
    choice => choice.ChosenStep.NextStepChoice, 
    choice => choice); 

これは理想的であること、そしてそれがIObservable<IWizardStepChoice<T>>いうよりIWizardStepChoice<T>だから、明らかにコンパイルされませんが、私は後だ出力が、NextStepChoiceセレクタを生成します。

私はAggregateScanを使用して見てきたが、これらは多くの倍駆動の操作であるとして、私は唯一の開始要素を持っている、それは私がALA Generateを探しています展開]ですが、私はそれをする必要があります入れ子にされた観察可能なものを評価することができる。

Observable.Createはおそらく私が利用できるものでしょうか?私はそれを試してみましたが、作ってみた:

一見、それは右に見えるので、私は、 IWizardStep<T>->IReadOnlyList<IWizardStep<T>>をしたいすべての権利の署名を持っていますが、それは動作しません
Path = CurrentStep.Select(_ => Observable.Create<IWizardStep<T>>(async observer => 
{ 
    IWizardStepChoice<T> next = new WizardStepChoice<T>(start, null); 
    observer.OnNext(next.ChosenStep); 
    while (next != null) 
    { 
     next = await next.ChosenStep.NextStepChoice; 
     observer.OnNext(next.ChosenStep); 
    } 
    observer.OnCompleted(); 
    return Disposable.Empty; 
}).Aggregate(new List<IWizardStep<T>>(), 
(l, s) => 
{ 
    l.Add(s); 
    return l; 
})).Switch().Publish().RefCount(); 

。それは始動することができますが、待ってから戻ってこないとハングアップします。

は私が近いんだ気持ちを持って、これはスケジュールの問題なので、私の質問は本当にこのです:

  1. これを解決する最良の方法は何ですか、私は閉じていますか?
  2. これが正しい場合、なぜ待ち時間に問題があり、どのように解決できますか?

更新

私はのawaitの可能性が高いという観測可能なようにぶら下がっていることに気づいた工夫を少しはまだありませんでした(とするつもりはなかった)値を放出した後(当たり前 )、私は今ウィザードの始めに値を使って各ステップを初期化することで解決しました。

私も正気-確認IWizardStep<T>にプロパティを追加することによって、これをしました - だけでフックアップされてIWizardStepChoice<T> LatestStepChoice {get;}

NextStepChoice.Subscribe(c => _latestStepChoice = c);

これは、ステップクラス自体で行われ、私はそれを確認することができますうまく働いている。

はなおさらインクルードはハングを待っていたので、私が試した:

  1. はそう.Subscribe()を呼び出すのawaitの値になるだろう、それReplay(1)作る - これは何かが加入している場合でも、それRepeat()作る
  2. を動作しませんでしたそれは新しい価値を見るでしょう - これはちょうどすべてのものをハングアップさせました。

明らかに私はのawaitが観測を照会するとき、それは私がReplay(1)が実現するだろうと思ったものです見て、最新の値を、与えられますように私はそれをしたい、ここで何かが欠けています。私もPublishLast()を試しましたが、AsyncSubject<T>のふるまいのために将来の更新が尊重されません。

今のところ私は自己申込みのプロパティを使用するように切り替えましたが、それは理想的ではありません。私が助けることができれば、オブザーバブルを照会することから抜け出す必要はなく、 "ハッキー"

+0

あなたが探しているものの署名を投稿することができますか?ウィザードのステップの観測は熱くなっていますか? – Shlomo

+0

@Shlomo私は、IWizardStepに行くことができるようにしたい - > IReadOnlyList >それは私がそれを周りに得たように、ちょうどステップクラスを自己観察して選択可能にして、私は通常アクセスすることができますプロパティ。 – Clint

+0

関数を再帰的なデータ構造から再帰的なデータ構造のリストにするのは何ですか? – Shlomo

答えて

2

再帰的な散歩は、単一の観測可能に観測のツリーを変換することができます:

static IObservable<IWizardStep<T>> Walk<T>(IWizardStep<T> step) 
    { 
     if (step?.NextStepChoice == null) 
      return Observable.Return(step); 

     return step.NextStepChoice.SelectMany(choice => Walk(choice.Step)).StartWith(step); 
    } 

使用法:

var steps = await Walk(step).ToArray(); 
+0

これは私がやったこととほぼ同じです。最終的には、異種の状態をすべて単一の不変の状態オブジェクトに統合して確定した後、それを観察します。これは、構築時には必須の列挙型ベースの再帰的な歩行、および他の情報を抽出する。また、スケジューリングに関する懸念が大幅に簡素化され、コードの理由が簡単になりました。 – Clint

関連する問題