私はRx for .NETを学習しています。同僚は私に始めて簡単な例を送っていますが、醜いものがあります。Rx .NET:タスクが完了するまで観測可能なフィルタ
コード:
using System;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections.Generic;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public IObservable<Content> contentStream;
public static bool isRunning = false;
public Form1()
{
InitializeComponent();
contentStream = Observable.FromEventPattern<ScrollEventArgs>(dataGridView1, "Scroll") // create scroll event observable
.Where(e => (dataGridView1.Rows.Count - e.EventArgs.NewValue < 50 && !isRunning)) //discart event if scroll is not down enough
//or we are already retrieving items (isRunning)
.Select(e => { isRunning = true; return 100; }) //transform to 100--100--100--> stream, discart next events until we finish
.Scan((x, y) => x + y) //get item index by accumulating stream items
.StartWith(0) //start with 0 before event gets triggered
.SelectMany(i => getContent(i).ToObservable());//create a stream with the result of an async function and merge them into just one stream
contentStream.Subscribe(c => invokeUpdateList(c)); //just update the control every time a item is in the contentStream
}
async private Task<Content> getContent(int index)
{
await Task.Delay(1000);//request to a web api...
return new Content(index);//mock the response
}
private void invokeUpdateList(Content c)
{
dataGridView1.Invoke((MethodInvoker)delegate
{
updateList(c);
});
}
private void updateList(Content c)
{
foreach (var item in c.pageContent)
{
dataGridView1.Rows.Add(item);
}
isRunning = false; //unlocks event filter
}
}
public class Content
{
public List<string> pageContent = new List<string>();
public const string content_template = "This is the item {0}.";
public Content()
{
}
public Content(int index)
{
for (int i = index; i < index + 100; i++)
{
pageContent.Add(string.Format(content_template, i));
}
}
}
}
私は好きではない何がisRunning
フィルタです。コントロールが更新されるまで、ストリーム内のいくつかのイベントを切り捨てるより良い方法はありますか? @Shlomoアプローチは右のようですが
それが負荷に移入起動しない:
var index = new BehaviorSubject<int>(0);
var source = Observable.FromEventPattern<ScrollEventArgs>(dataGridView2, "Scroll")
.Where(e => dataGridView2.Rows.Count - e.EventArgs.NewValue < 50)
.Select(_ => Unit.Default)
.StartWith(Unit.Default)
.Do(i => Console.WriteLine("Event triggered"));
var fetchStream = source
.WithLatestFrom(index, (u, i) => new {unit = u,index = i })
.Do(o => Console.WriteLine("Merge result" + o.unit + o.index))
.DistinctUntilChanged()
.Do(o => Console.WriteLine("Merge changed" + o.unit + o.index))
.SelectMany(i => getContent(i.index).ToObservable());
var contentStream = fetchStream.WithLatestFrom(index, (c, i) => new { Content = c, Index = i })
.ObserveOn(dataGridView2)
.Subscribe(a =>
{
updateGrid(a.Content);
index.OnNext(a.Index + 100);
});
私が見ることができ、出力ログに「イベントをトリガー」が、私はWithLatestFrom
に達すると最初source
要素(StartWith(Unit.Default)
)が失われているようです。
あなたのアプローチはうまくいくようですが、 'index.OnNext(0)'のときにグリッドにデータを入力しません。何とか 'StartWith(Unit.Default)'が失われてしまった。私がイベントジェネレータとしてボタンを使用すると、グリッドは 'StartWith'でもクリックする前から入力されます。何が起こっているのでしょうか? – jlvaquero
が編集されました。私は 'Subject'の代わりに' BehaviorSubject'を使うべきでした。私はそれを切り替えて、 'index.OnNext(0);'呼び出しを削除しました。これは現在不要です。 – Shlomo
'StartWith(Unit.Default)'ではまだ動作しません。私は 'DistinctUntilChanged()'の下に 'StartWith(0)'を使ってロード時に値を設定しなければなりませんでした。 – jlvaquero