3

Jeff Van Gogh のブログの Reactive Extensions for javascript のデモを見て、C#/Winforms で試してみようと思ったのですが、うまく機能していないようです。

これをフォームのコンストラクターに投げました(Rxフレームワークがインストールされ参照されています):

Observable.Context = SynchronizationContext.Current;
var mousemove = Observable.FromEvent<MouseEventArgs>(this, "MouseMove");
var message = "Time flies like an arrow".ToCharArray();

for(int i = 0; i < message.Length; i++)
{
    var l = new Label() 
            { 
                Text = message[i].ToString(), 
                AutoSize = true, 
                TextAlign = ContentAlignment.MiddleCenter 
            };
    int closure = i;
    mousemove
        .Delay(closure * 150)
        .Subscribe(e => 
            {
                l.Left = e.EventArgs.X + closure * 15 + 10;
                l.Top = e.EventArgs.Y;
                //Debug.WriteLine(l.Text);
            });
    Controls.Add(l);
}

マウスを動かすと、文字がランダムな順序で移動するように見えます。デバッグ行のコメントを外すと、同じ文字に対して複数のイベントが表示されます...

何か案は?スロットルを試してみましたが、違いはないようです。これらすべてのラベルを移動するように WinForms に要求しすぎているのでしょうか?

( Rxフォーラムに投稿されたクロス)

4

1 に答える 1

2

Rxフォーラムから投稿された回答のクロス(作成者がここにいて、それを主張したい場合は、私はそれで問題ありません):

問題#1:古いビットを使用しています。Observable.Contextは約4バージョン前になくなりました。問題#2:Javascriptにはスレッドの概念がなく、Rxは他のスレッドに何かを置くのが好きです。

したがって、最新のビットを使用すると、ソリューションは次のようになります。

void Form1_Load(object sender, EventArgs e)
{
   Reactive("Time flies like an arrow");
}

private void Reactive(string msg)
{
    var mousemove = Observable.FromEvent<MouseEventArgs>(this, "MouseMove");
    var message = msg.ToCharArray();

    for(int i = 0; i < message.Length; i++)
    {
        var l = new Label()
        { 
            Text = message[i].ToString(), 
            AutoSize = true, 
            TextAlign = ContentAlignment.MiddleCenter 
        };
        int closure = i;
        mousemove
            .Delay(TimeSpan.FromSeconds(0.07 * i), Scheduler.Dispatcher)
            .Subscribe(e =>
            {
                l.Left = e.EventArgs.X + closure * 12 - 5;
                l.Top = e.EventArgs.Y + 15;
            });
        Controls.Add(l);
    }
}

ObserveOnDispatcherとSubscribeOnDispatcherに注目してください。これにより、Javascriptバージョンに近づきますが、ここでもスレッド化が実際の問題です。

更新、上記のコードにジェフ・ヴァン・ゴッホからの修正を追加


楽しみのために、Rxなしの同じものの漠然としたレンダリングを次に示します。

private void Unreactive(string msg)
{
    var message = msg.ToCharArray();

    for(int i = 0; i < message.Length; i++)
    {
        var l = new Label()
        { 
            Text = message[i].ToString(), 
            AutoSize = true, 
            TextAlign = ContentAlignment.MiddleCenter 
        };
        Controls.Add(l);
        int closure = i;
        this.MouseMove += (s, e) => LabelDelayMove(closure, e, l);
    }
}

private void LabelDelayMove(int i, MouseEventArgs e, Label l)
{
    Point p = new Point(e.X + i * 12 - 5, e.Y - 15);
    var timer = new System.Threading.Timer((_) => LabelMove(l, p), null, i * 70, System.Threading.Timeout.Infinite);
}

private void LabelMove(Label l, Point location)
{
    this.BeginInvoke(new Action(() => l.Location = location));
}
于 2010-03-18T12:51:35.820 に答える