joe shum
joe shum

Reputation: 17

Rx Subscribe issue, how to update data in UI control in winform

I would like to do a little project to do some calculation and add the calculated results in listbox.

My code:

     int SumLoop(int lowLimit, int highLimit)
        {
            int idx;
            int totalSum = 0;
            for (idx = lowLimit; idx <= highLimit; idx = idx + 1)
            {
                totalSum += idx;
            }
            return totalSum;
        }

   private void button1_Click(object sender, EventArgs e)
        {
            var test2 = Observable.Interval(TimeSpan.FromMilliseconds(1000)).Select(x=>(int)x).Take(10);

            test2.Subscribe(n => 
                {
                    this.BeginInvoke(new Action(() =>
                        {
                            listBox1.Items.Add("input:" + n);
                            listBox1.Items.Add("result:" + SumLoop(n,99900000));
                        }));
                });
        }

The result:

input:0
result:376307504
(stop a while)
input:1
result:376307504
(stop a while)
input:2
result:376307503
(stop a while)
input:3
result:376307501
(stop a while)
....
...
..
.
input:"9
result:376307468

If i would like to modify the interval constant from 1000 --> 10,

var test2 = Observable.Interval(TimeSpan.FromMilliseconds(10)).Select(x=>(int)x).Take(10);
  1. The displaying behavior becomes different. The listbox will display all inputs and results just a shot. It seems that it waits all results to complete and then display everything to listbox. Why?

  2. If i would like to keep using this constant (interval:10) and dont want to display everything just a shot. I want to display "Input :0" -->wait for calculation-->display "result:376307504".... So, how can i do this?

Thankx for your help.

Upvotes: 0

Views: 1373

Answers (2)

Tim
Tim

Reputation: 970

If I understand you correctly you're wanting to run the sum loop off the UI thread, here's how you would do that:

Observable
    .Interval(TimeSpan.FromMilliseconds(1000))
    .Select(x => (int)x)
    .Select(x => SumLoop(x, 99900000))
    .Take(10)
    .ObserveOn(listBox1) // or ObserveOnDispatcher() if you're using WPF
    .Subscribe(r => {
        listBox1.Items.Add("result:" + r);                  
    });

You should see the results trickle in on an interval of 10ms + ~500ms.

Upvotes: 3

Judah Gabriel Himango
Judah Gabriel Himango

Reputation: 60001

Instead of doing control.Invoke/control.BeginInvoke, you'll want to call .ObserveOnDispatcher() to get your action invoked on the UI thread:

Observable
   .Interval(TimeSpan.FromMilliseconds(1000))
   .Select(x=>(int)x)
   .Take(10)
   .Subscribe(x => {
      listBox1.Items.Add("input:" + x);
      listBox1.Items.Add("result:" + SumLoop(x, 99900000));                  
   });

You said that if you change the interval from 1000 ms to 10ms, you observe different behavior.

The listbox will display all inputs and results just a shot.

I suspect this is because 10ms is so fast, all the actions you're executing are queued up. The UI thread comes around to execute them, and wham, executes everything that's queued.

In contrast, posting them every 1000ms (one second) allows the UI thread to execute one, rest, execute another one, rest, etc.

Upvotes: 0

Related Questions