Sometimes, we need to have an IObservable
subscription run at a specific time. Imagine having to synchronize events across servers in geographically different areas and time zones. You might also need to read data from a queue while preserving the order in which the events occur. Another example would be to perform some kind of I/O task that could take some time to complete. Schedulers come in very handy in these situations.
Additionally, you can consider reading up more on using schedulers on MSDN. Have a look at https://msdn.microsoft.com/en-us/library/hh242963(v=vs.103).aspx.
winformRx
. Open the form designer and in Toolbox, search for the TextBox control and add it to your form:Throttle
keyword. Add a subscription to the searchTerm
variable, writing the result of the text input to the label control's text property:private void Form1_Load(object sender, EventArgs e) { var searchTerm = Observable.FromEventPattern<EventArgs>(textBox1, "TextChanged") .Select(x => ((TextBox)x.Sender).Text) .Throttle(TimeSpan.FromMilliseconds(5000)); searchTerm.Subscribe(trm => label1.Text = trm); }
Observable
interface is running a timer from System.Threading
, which isn't on the same thread as the UI. Luckily, there is an easy way to overcome this. Well, it turns out that the UI-threading capabilities lie in a different assembly, which we found easiest to get via the Package Manager Console:PM> Install-Package System.Reactive.Windows.Forms
Please note that you need to ensure that the Default project selection is set to winformRx
in the Package Manager Console. If you don't see this option, resize the Package Manager Console screen width until the option is displayed. This way you can be certain that the package is added to the correct project.
searchTerm.Subscribe(trm => label1.Text = trm);
, which does the subscription, to look like this:searchTerm.ObserveOn(new ControlScheduler(this)).Subscribe(trm => label1.Text = trm);
You will notice that we are using the ObserveOn
method here. What this basically tells the compiler is that the this
keyword in new ControlScheduler(this)
is actually a reference to our Windows Form. Therefore, ControlScheduler
will use the Windows Forms timers to create the interval to update our UI. The message happens on the correct thread, and we no longer have our cross-thread violation.
System.Reactive.Concurrency
namespace to your project, Visual Studio will underline the ControlScheduler
line of code with a squiggly line. Pressing Ctrl + . (the Control key and dot) will allow you to add the missing namespace:System.Reactive.Concurrency
contains a scheduler that can talk to Windows Forms controls so that it can do the scheduling. Run your application again and start typing some text into your text box:What we need to keep in mind here from the code we created is that there are ObserveOn
and Subscribe
. You should not confuse the two. In most cases, when dealing with schedulers, you will use ObserveOn
. The ObserveOn
method allows you to parametrize where the OnNext
, OnCompleted
, and OnError
messages run. With Subscribe
, we parameterize where the actual subscribe and unsubscribe code runs.
We also need to remember that Rx use the threading timers (System.Threading.Timer
) as a default, which is why we encountered the cross-thread violation earlier. As you saw though, we used schedulers to parameterize what timer to use. The way schedulers do this is by exposing three components. These are:
The use of a clock is important because it allows the developer to use timers on remote machines, for example (where there might be a time difference between you and them), to tell them to perform an action at a particular time.
3.141.3.175