Chapter 18. Reactive Extensions for .NET

For developers, the computing world of today is becoming much more concurrent than just a few short years ago. Computer users expect an ever-increasing computational power from their electronic gadgets, including their mobile devices. Unfortunately, it seems that the only way manufacturers will be able to increase computational speed in the near future is through adding additional processors (instead of making a single processor faster, as has been the case over the last few decades). In the case of processors on personal computers, the industry has already hit a proverbial brick wall, having pretty much reached the maximum computational capacity available on a single processing unit. An average personal computer today comes with two or more processing units, and the number is certain to increase.

Mobile devices still have some processing speed to grow into before they max out the processing power of a single CPU. However, the average phone will soon have several processing units as well. In addition, uninterrupted Internet access on the phone is assumed—resources needed for proper functioning of an application may be spread around the world (in the cloud), but the user is rarely aware of that. A phone application should have the ability to access those resources seamlessly as needed—i.e., it should not stop accepting all input from the user while these resources are accessed. Rather, an application should retrieve the resources without interrupting other functionality of an application—in other words, it should obtain these resources asynchronously. The future for both personal computers and mobile devices is both concurrent and asynchronous.

How do you approach concurrent and asynchronous programming on Windows Phone 7? The answer is, certainly, with great caution, since it's not easy. To help tame that complexity, a powerful framework emerged on the .NET scene at the end of 2009. That framework, called the Reactive Extensions for .NET (also known as Rx.NET), is now available for Windows Phone 7 and provides sophisticated mechanisms to make event processing and asynchronous programming more intuitive. In this chapter, you will learn the concepts behind Reactive Extensions for .NET and build two simple applications using the Rx.NET framework. The first will search and retrieve images on Flickr asynchronously. The second will display the current weather after accepting a ZIP code as input from the user. As with several other chapters of this volume, a whole book could be written on the subject of Reactive Extensions alone, especially since there is a version of Reactive Extensions for JavaScript available as well.

In this chapter, you will learn the basics of Rx.NET and, we hope, leave with a basic understanding and appreciation of this technology. However, to leverage the power of Rx.NET, you need a good understanding of LINQ. Although the examples in this chapter should be relatively easy to understand for the novice C# programmer even without an in-depth knowledge of LINQ, for expert coverage of the topic we recommend the excellent book Pro LINQ: Language Integrated Query in C#2008 by Joseph C. Rattz (Apress, 2008). Another good resource is "101 LINQ Samples," available for free online at http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx. Rx.NET also relies heavily on general object-oriented principles; if the concept of interfaces is not familiar to you, it may be a good idea to understand those before reading this chapter. Finally, Rx.NET constructs make extensive use of the newer concepts of the .NET Framework, such as lambda expressions and extension methods. While it will be possible to follow examples in this book without in-depth understanding of either of those concepts, to leverage the power of Rx.NET on your own, you will have to know these features of the .NET Framework.

The power of Reactive Framework can be applied to deal with a wide range of computational issues. This chapter will focus on the way that the framework deals with a problem that is probably as old as the personal computer: how do you provide a responsive user interface while utilizing the full computational resources available? And how can you do so in a manner that makes code readable and easy to manage/maintain?

Note

The initial release of Rx.NET libraries comes pre-installed on the operating system of every Windows Phone 7 device. However, just like any other technology, the Reactive Extensions library is constantly being enhanced to deliver even more power to the developers. As a Windows Phone 7 developer, you are not "stuck" having to use the version of Rx.NET that comes preinstalled on the devices—you can always go to the Microsoft Data Developer Center (http://msdn.microsoft.com/en-us/data/gg577609) and download the latest libraries available for the phone. Once you reference and use them, they will be distributed together with your application, slightly increasing its footprint.

Introducing Reactive Programming

Rx.NET aims to revolutionize reactive programming in the .NET Framework. In reactive programming, you register an interest in something and have items of interest handed over, or pushed to the attention of the application, asynchronously, as they become available. A classic example of an application that relies heavily on the reactive programming model is the spreadsheet, where an update to a single cell triggers cascading updates to every cell that references it. This concept of having things pushed down as they become available is particularly well suited to applications that use constantly changing data sources, such as the weather application that you will be building in this chapter.

Reactive programming is often contrasted with interactive programming, where the user asks for something and then waits for it until it is delivered. To help further differentiate these concepts, let's take a look at a car shopping analogy. Usually, when shopping for a car, you go to a car dealership (or look online) and look at different car makes and models. You pick the ones you like and test-drive them. This arrangement is an example of interactive programming, where you asked for a car and got it in return. In a reactive approach to car shopping experience, you would send a note to a dealership expressing interest in a certain make and model and then continue going on with your daily routine. The dealer locates items of interest and notifies you when they become available.

Let's see if we can carry over this analogy to event processing on Windows Phone 7. For the sample application that you will be building later in this chapter, you will want to read the contents of a text box once it can be determined that no keystroke has occurred a half a second since the previous one. In the sample, this will be taken to mean that the user has finished typing and is ready for the application to do something. If you were to use an interactive approach, you would implement this by wiring up the KeyDown event for the text box, and then checking some sort of timer to see whether enough time had elapsed between keystrokes. In a reactive approach, as you will see shortly, things are much simpler: you express interest in being notified of KeyDown events only after a half-second has elapsed between a user's keystrokes. Once notified of such an event, you take action—searching for photos online, in this case. Before you learn how to search for photos in a reactive manner, however, you will walk through several short examples to get a feeling for how Reactive Extensions implement the core Observer pattern, which forms the basis of the Reactive Framework and is described in detail in the following sidebar.

Rx.NET Subscription Pipeline

To use Rx.NET, there are four basic steps that you have to follow to designate observables and create observers.

  1. First, you build or define an Observable (or Subject, as it is called in the Observer pattern described in the sidebar).

  2. Then, you subscribe to that Observable (or create an Observer if you follow along with the Observer pattern in the sidebar).

  3. Next, you receive data and act on it for as long as the Subject continues to notify the Observer.

  4. Finally, when there are no more notifications from the Subject to process, the Observer unsubscribes from the Subject by calling the Dispose method.

Rx.NET defines two new interfaces to accommodate this subscription pipeline: IObservable and IObserver. You will learn how to use these interfaces in the next few sections.

Implementing the Observer Pattern with Rx.NET

Before you create an application that asynchronously searches photos on Flickr, you will take a short detour to understand the basics of Rx.NET. In the project that follows, you will generate a simple Observable collection using Reactive Extensions for .NET and read values from this collection as they are pushed down to you. Follow these step-by-step instructions.

Creating a Windows Phone Project

First, you will create a new Windows Phone 7 project and add framework elements necessary to make it work on the mobile platform.

  1. Launch Visual Studio 2010 Express for Windows Phone and create a new Windows Phone Application project. Name it RxSample.

    In this project, you will observe the messages generated by the Reactive Extensions framework in the text box on the phone screen.

  2. From the Toolbox, select the textblock and drop it on the design surface. Since you are just getting your feet wet with Rx.NET, leave the name of the textblock (textBlock1) unchanged for now and adjust its height and width to occupy the full area of the screen. Highlight the textblock, press F4 to bring up its Properties window, and set the TextWrapping property to Wrap.

    On Windows Phone 7, the Rx.Net implementation is contained within two separate assemblies –Microsoft.Phone.Reactive and System.Observable.

  3. Add a reference to Microsoft.Phone.Reactive and System.Observable assemblies by right-clicking and selecting Add Reference.

Adding Code to Create and Read Observable Collections

You will now add code to create an Observable collection, subscribe to it, and read values from it.

  1. Import the Rx.NET libraries to current code. To do that, open MainPage.xaml.cs (right-click MainPage.xaml and select View Code) and add the following statement to the top of the page:

    using Microsoft.Phone.Reactive;

    Remember how an Observable collection performs the role of the Subject in the Observer pattern. In Rx.NET, the IObservable<T> interface acts as that Subject. You will now create an Observable collection that will consist of a range of integer values.

  2. In the MainPage() constructor, add the following code right after the InitializeComponent() statement:

    IObservable<int> source = Observable.Range(5, 3);

    Notice the use of the Observable.Range method to create an Observable collection that will consist of a range of integers from 5 to 7 inclusive (the Range method created three sequential values, from 5 to 7 inclusive).

    You will now create an Observer for the source Subject created in Step 2. This Observer object will be notified of any changes to the source—in this case, every time a new integer is generated, or "pushed down" to the application. Notice that the Observer object implements IDisposable interface as well.

  3. Add the following code to create the Observer:

    IDisposable subscription = source.Subscribe(x =>
            textBlock1.Text += String.Format(" OnNext: {0}", x),
            ex => textBlock1.Text += String.Format(" OnError: {0}", ex.Message),
            () => textBlock1.Text += " OnCompleted");

    The Subscribe method of IObservable<T> has several overloads; the one that you just used accepts three lambda expressions (see the "Lambda Expressions" sidebar) as its parameters: the first lambda expression contains the logic to invoke when another element becomes available to the Observer (OnNext), the second has logic to invoke if there is an exception in the Observer (OnError), and the last one contains logic that gets executed when the Subject completes its useful life (OnComplete). The "completion of useful life" condition varies from Subject to Subject, but generally means that there are no more elements to receive from the Subject. If you're not familiar with lambda expressions, the sidebar contains a brief introduction to this newer feature of the .NET Framework.

  4. Finally, tell the Observer to discontinue its interest in the Subject's state by issuing a Dispose() method:

    subscription.Dispose();
  5. Press F5 to run the application. The Windows Phone 7 emulator screen will appear, showing messages OnNext: 5, OnNext: 6, OnNext: 7, and OnComplete, as shown in Figure 18-1. The Observable object generated three integer values, pushed them down to Observers, and called it quits.

Reactive Extensions for .NET first steps

Figure 18.1. Reactive Extensions for .NET first steps

In the previous code, notice how subscription does not implement the IObserver<T> interface. That is because the Microsoft.Phone.Reactive assembly contains a set of extension methods that overload the Subscribe() method of IObservable. These overloaded methods accept OnNext, OnError, and OnCompleted handlers defined by the IObserver<T> interface as lambda expressions, just as described in the previous paragraphs. Hence, in your experiments and samples with Rx.NET in this chapter, you will not have to physically implement the IObserver<T> interface.

The output of your first Rx.NET application (shown in Figure 18-1) is certainly nothing spectacular. But you are just barely skimming the Rx.NET surface here. Imagine subscribing to events, such as keystrokes or data emitted by the location service. Then, imagine having the ability to react to those events only if certain conditions are met. For instance, filter out location values so that only when the location specifies a certain predefined area, the event is raised. In the next section, you will build a small application that uses this filtering approach to make an asynchronous web service call to Flickr once the user has stopped typing text for half a second.

Using Rx.NET Event Handling to Search for Flickr Photographs

In this section, you will build an application that searches Flickr photos asynchronously using Rx.NET. In particular, you will learn how to create Observable data sources from events, as well as how to subscribe to them. The version of Flickr search you'll create is shown in Figure 18-2. The search technique is basic and uses a WebBrowser control to display images; however, this example will allow you to concentrate on learning the Rx.NET techniques for processing events on the Windows Phone 7. In the next example, you will build a Weather Service application that will demonstrate asynchronous programming with Rx.NET. Let's get started.

Creating a Windows Phone Project

First, create a new Windows Phone 7 project for the Flickr image search.

  1. Launch Visual Studio 2010 Express for Windows Phone and create a new Windows Phone Application project. Name it FlickrRx.

  2. Change the name of the application to Flickr Search, and change the page title to "Rx at Work" (to accomplish this, highlight the application name, press F4, edit the Text property, and then do the same for the page title).

  3. Add a reference (by right-clicking and selecting Add Reference) to Microsoft.Phone.Reactive and System.Observable assemblies.

Flickr Search with Rx.NET

Figure 18.2. Flickr Search with Rx.NET

Adding a User Interface

Now, add some user interface elements to the project. The user interface will consist of a text box, a label, and a WebBrowser control, as shown in Figure 18-3.

  1. From the Toolbox, select a text box and drop it on the design surface. Rename the text box to txtSearchTerms. Make the width of the text box equal the width of the screen and clear the Text property. Next, select a textblock, drop it underneath the text box, rename it lblSearchingFor, and resize it to be the width of the screen.

  2. From the Toolbox, select the WebBrowser control and drop it on the design surface underneath the textblock. Rename the WebBrowser control webResults and make it the width of the screen.

You should now have something similar to Figure 18-3.

Flickr Search using Rx.NET screen layout

Figure 18.3. Flickr Search using Rx.NET screen layout

Adding Logic to Search Flickr for Images

The next step is to add logic to populate the WebBrowser controls with the results of a Flickr image search.

  1. Open MainPage.xaml.cs (right-click MainPage.xaml and select View Code) and paste the following using statement at the top of the page:

    using Microsoft.Phone.Reactive;

    Now, write code to capture the KeyUp events of the text box. To accomplish this, you will use the FromEvent method of the Rx.NET library, which accepts the name of the object to capture events for, as well as name of the event on that object.

  2. Paste the following code immediately following the InitializeComponent() statement in the MainPage() constructor:

    var keys =  Observable.FromEvent<KeyEventArgs>(txtSearchTerms, "KeyUp");
    
    keys.Subscribe(evt =>
    {
      lblSearchingFor.Text = "Searching for ..." + txtSearchTerms.Text;
    webResults.Navigate(new Uri("http://www.flickr.com/search/?q="
      + txtSearchTerms.Text));
    });

    The first statement creates an Observable data source, keys that will consist of all KeyUp events of the txtSearchTerms text box. The second statement is a lambda expression that creates an Observer on this collection and attempts to update the lblSearchingFor textblock with the text entered into the text box and show the web page representing the results of searching Flickr with the text supplied in the text box. Note the { symbol within the lambda expression—that symbol is used to define a lambda expression whose body has more than one statement within it, as you do in the previous example.

  3. Press F5 to run the application. As you type the first character, you should see the WebBrowser control attempting to navigate to the Flickr search page specifying the only character entered as its search criteria. Notice how there is very little visual indication that there's some search or navigation performed behind the scenes. You will improve on that in the sections that follow, where you will create an animation to play while the WebBrowser control is loading with the results of an image search.

Enhancing a Flickr Search with Throttling

At this point, you must certainly be wondering what Rx.NET has added to your toolbox besides the complexities of the Observer pattern. Couldn't you do pretty much everything you have done so far using the standard event handling procedures available to Microsoft developers since the earliest days of Visual Basic (before there ever was VB.NET, that is)? The answer is: Rx.NET has added nothing up until now, and yes, you could have done everything with VB. The power of Reactive Extensions for .NET starts to come through in the next few steps of the example.

First, modify the application as follows:

  1. Change the code line declaring an Observable collection above from

    var keys =  Observable.FromEvent<KeyEventArgs>(txtSearchTerms, "KeyUp");

    to

    var keys = Observable.FromEvent<KeyEventArgs>(txtSearchTerms,
                   "KeyUp").Throttle(TimeSpan.FromSeconds(.5));
  2. Change the code block declaring an Observer from

    keys.Subscribe(evt =>
    {
            lblSearchingFor.Text = "Searching for ..." + txtSearchTerms.Text;
            webResults.Navigate(new Uri("http://www.flickr.com/search/?q="
            + txtSearchTerms.Text));
    });

    to

    keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
             {
                    if (txtSearchTerms.Text.Length>0)
    {
                          lblSearchingFor.Text = "Searching for ..." +
    txtSearchTerms.Text;
                          webResults.Navigate(new Uri("http://www.flickr.com/search/?q="
    +
                          txtSearchTerms.Text));
                    }
             });
  3. Press F5 to run the application. Click the text box and enter the search terms for photo lookup in Flickr (for example, Barcelona) and watch the WebBrowser control retrieve the images of that beautiful European city from Flickr.

    Let's examine the code that you added in the last section. You created an observable collection that consists of all of the KeyUp events generated on txtSearchTerms text box. When you added the Throttle(.5) statement, you effectively told Rx.NET that you wanted to observe only KeyUp events that occur more than half a second apart (0.5 seconds). Assume that an average user will be pressing the keys on the keyboard less than half a second apart; so a half-a-second pause between key presses will tell the application that the user is ready for the Flickr search to launch and the user is ready to "observe" the results of its execution.

    In Step 2, you enhanced the application in two ways. First, you added logic not to invoke image search if nothing is entered in the text box (this could happen if the user erased the content with the Backspace key). Second, notice the ObserveOn(Deployment.Current.Dispatcher) construct that was used to help create an Observer. To understand its reason for being and to allow you to peek under the hood of Rx.NET, remove it. As a result, your code for Step 2 will look like the following snippet:

    keys.Subscribe(evt =>
                {
                    if (txtSearchTerms.Text.Length > 0)
                    {
                        lblSearchingFor.Text = "Searching for ..." +txtSearchTerms.Text;
                        webResults.Navigate(new Uri("http://www.flickr.com/search/?q=" +
    txtSearchTerms.Text));
                    }
                });
  4. Press F5 to run the application now, and you will see the screen shown in Figure 18-4, where Visual Studio displays an "Invalid cross-thread access" message.

What is happening, as readers familiar with programming User Interface (UI) on the .NET platform know, is that updating UI from a thread other than a UI thread is a tricky undertaking. Under the hood, Reactive Extensions for .NET has created a separate background thread and will be pushing notifications of changes from the Observable data source to the Observers from that thread. This background thread can't modify the UI thread directly.

An invalid cross-access thread exception is generated when trying to update UI directly from the background thread.

Figure 18.4. An invalid cross-access thread exception is generated when trying to update UI directly from the background thread.

Fortunately, the creators of Rx.NET have provided a solution to this problem by giving us the ObserveOn() extension method in the Microsoft.Phone.Reactive assembly. This extension method has several overloads, and one of them accepts a Dispatcher object. In the .NET Framework, a Dispatcher object maintains a prioritized queue of work items on a specific thread, and here it provides a way for you to observe an Observable data source on the UI thread. In the preceding example, you pass the Deployment.Current.Dispatcher property to the ObserveOn() method to get thread-safe access to the current Dispatcher and use it to update visual elements on the phone. The use of a single ObserveOn() method is significantly easier than dealing with the Dispatcher's Invoke method, which is a common way to update UI in multi-threaded Silverlight and WPF applications.

Adding an Animation that Plays as Flickr Images Load

You can further enhance the Flickr image search application by adding a simple animation that will play while the web pages with the results of your image search are loading. To do that, you will create an animation in Expression Blend for Windows Phone, subscribe to the Navigated event of the WebBrowser control, and play the animation in code.

Follow these steps to add this feature to your project:

  1. Still in Visual Studio for Windows Phone, add a textblock to the phone's design surface and place it between the "Searching for" textblock and the WebBrowser control. Name that textblock lblLoading, set the caption to "Loading Images," and set its Visibility property to Collapsed.

    Microsoft Expression Blend for Windows Phone is a powerful application for creating and editing graphics and animations for Windows Phone 7 devices. You have used it in the first part of this book to style controls and for other graphical tasks.

  2. To launch Expression Blend and load it with the Flickr project, right-click MainPage.xaml in Visual Studio and select Open in Expression Blend. Microsoft Expression Blend launches with your solution open and ready to edit.

    Your animation will be a progress bar in the form of a rectangle that will grow in width as the time passes. This animation will loop indefinitely, so that when it reaches maximum allowable size, the rectangle will go back to its beginning and the animation will be repeated.

  3. In Expression Blend, select a Rectangle from the Toolbox, draw a very narrow, almost invisible rectangle right next to the Loading Images textblock, and set its Fill color to red.

    Now, create what is called a timeline animation in Expression Blend. Timeline animations are created with the use of the storyboards, so you will create a new storyboard in this step.

  4. In the Objects and Timeline window, click the New button (shown in Figure 18-5), name the storyboard loadingImages, and click OK.

    The Objects and Timeline panel will now change to display a timeline, and Blend is ready to record your animation.

  5. Select the rectangle that you placed on the Windows Phone design surface and click the Record Keyframe button, as shown in Figure 18-6.

  6. Next, move the Animation Playhead (the yellow vertical line in the Timeline) to about 1.5 seconds, as shown in Figure 18-7. Click the Record Keyframe button again, and then resize the rectangle to be close to the full phone screen width.

    Now you will now set the animation to loop as long as it is active.

  7. In Objects and Timeline, click and select the loadingImages storyboard name. Common Properties for the Storyboard dialog appears. Select "Forever" in the Repeat Behavior property of this storyboard.

    With the animation now complete, you are ready to show it when the user performs a search for Flickr images.

    Creating a new storyboard animation in Expression Blend

    Figure 18.5. Creating a new storyboard animation in Expression Blend

  8. Save everything in Expression Blend (File

    Creating a new storyboard animation in Expression Blend

Now you will add code to first show the animation when the search for images is initiated and then stop the animation once that search is complete.

To start the animation once the user initiates search for Flickr images, you will call the Begin method of the loadingImages animation.

In MainPage.xaml.cs, change the code that creates an Observer for the KeyUp event to the following:

keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
            {
                if (txtSearchTerms.Text.Length > 0)
                {
                        lblSearchingFor.Text = "Searching for ..." + txtSearchTerms.Text;
                        lblLoading.Visibility=System.Windows.Visibility.Visible;
                        loadingImages.Begin();

                webResults.Navigate(new Uri("http://www.flickr.com/search/?q=" +
                        txtSearchTerms.Text));
                        }
            });
Beginning of the Loading Images timeline animation

Figure 18.6. Beginning of the Loading Images timeline animation

Once the images load in the WebBrowser control, you will stop the animation by calling the Stop method of the loadingImages animation. To accomplish this, you will use Rx.NET to subscribe to the web browser's Navigated event. Once this subscription receives data, you will stop the animation. The following code accomplishes these tasks.

End of the Loading Images timeline animation

Figure 18.7. End of the Loading Images timeline animation

  1. Paste the following code at the end of the MainPage constructor:

    var browser =
            Observable.FromEvent<System.Windows.Navigation.NavigationEventArgs>(webResults,
    "Navigated");
    
            browser.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
            {
                    loadingImages.Stop();
            lblLoading.Visibility = System.Windows.Visibility.Collapsed;
            });

    You are now ready to run the application.

  2. Press F5, type a keyword into the text box, and observe the animation while the images are being loaded into the browser.

You're still only scratching the surface of Rx.NET and its applications, but you can already see the power of this framework. Using Rx.NET, you can think of virtually any event as an observable data source, whether it's a location service that generates coordinate values (which you can think of as an observable set of position values), accelerometer data, key press events, or web browser events, such as those already demonstrated. Now that you have seen how to create Observable data sources from events using the FromEvent<T> method and how to subscribe to those events, we will expand upon this knowledge in the next section. Specifically, using Rx.NET, you will build a small real-time weather application that will use a publicly available web service to asynchronously retrieve current weather and show a small picture representing current weather for the zip code provided. But before you build this application, you will learn about general design guidelines for using Rx.NET from the Rx.NET Development team.

Rx.NET Design Guidelines

As a sign of maturing platform, Rx.NET has received its own set of design guidelines (available at http://go.microsoft.com/fwlink/?LinkID=205219) to help developers make best decisions when using the library. Some of the recommendations within that document have already been covered in this chapter; for instance, the general guideline to use Rx.NET for asynchronous and event-based computations. In the next few sections, you will get familiar with few more useful strategies for creating robust Rx.NET-based applications.

Consider Drawing a Marble Diagram

If you research Rx.NET on Microsoft web site (and specifically, Channel 9), chances are extremely high you will encounter references to what is known as Marble Diagrams. An example of a Marble Diagram is shown in Figure 18-8, where it depicts the use of the TakeUntil() operator in Rx.NET. In Marble Diagrams, we have input sequences of event-based and asynchronous data that we know about. Marble Diagram helps us understand what would happen to those input sequences as a result of application of Rx.NET operator.

Figure 18-8 is representative of the real-world example of receiving geolocation position on the phone. It assumes that there is data about phone user's location being gathered until the user types in a new location of interest to search for (such as searching for a Starbucks in the immediate neighborhood, for example). Initially, the top data sequence (geoLocationReading) receives data points (each data point is indicated by a small circle, or a marble, on the line corresponding to the geoLocationReading, in Figure 18-8). Then, newLocation sequence starts receiving data and the marbles are drawn on the line corresponding to the newLocation sequence. Notice how as a result of application of the TakeUntil() operator, the resulting sequence (result) gets only the data points (marbles on the line corresponding to the result sequence) of geoLocationReading until the marbles on the newLocation sequence started coming in. Regardless of how many data points (marbles) appeared on either geoLocationReading or newLocation sequences after that fact (indicated by an X in Figure 18-8), the result sequence did not get any additional data points after that fact.

Marble Diagram for the TakeUntil Rx.NET operator

Figure 18.8. Marble Diagram for the TakeUntil Rx.NET operator

As with the TakeUntil operator, you can analyze all of the Rx.NET operators by visualizing them on a Marble Diagram and understanding the resulting sequences they produce. Rx.NET design guidelines hint at another area where Marble Diagrams may be helpful: draw a marble diagram of the sequence you would like to create, and then you can deduct which Rx.NET operators you need to use to get to that marble diagram.

Consider Passing a Specific Scheduler to Concurrency Introducing Operators

We stated in the beginning of this chapter that Rx.NET has the power to make parallel programming easier. It does this by abstracting away many issues of threading and concurrency and handling concurrency in a declarative way (there is no need to explicitly create threads, for example). However, even with this concurrency abstraction, we have some control over how the execution of Rx.NET should proceed and the context of how the Rx.NET notifications should be processed. This brings us to a discussion about schedulers.

In Rx.NET, it is possible to schedule two things: (1) how (or what thread context) the subscription will execute and (2) how (what thread context) the notification will be published. This context is controlled by the SubscribeOn() and ObserveOn() extension methods of the IObservable<T> interface. Both of those extension methods can accept a property of the static Scheduler class, and the properties available for you to pass in are described next.

  • Scheduler.Dispatcher will force the execution on the Dispatcher, which is a class that owns the application thread and internally maintains a queue of work items.

  • Scheduler.NewThread will schedule all actions onto a new thread.

  • Scheduler.ThreadPool will schedule all actions onto the Thread Pool.

  • Scheduler.Immediate will ensure the action is executed immediately.

  • Scheduler.CurrentThread will ensure that the actions are performed on the thread that made the original call. This is not the same as Scheduler.Immediate, since actions scheduled on the current thread may be queued for later execution.

The following code is an example of how you would use the schedulers with subscriptions in Rx.NET—notice how you subscribe on a new thread and observe the results of the subscription on the dispatcher:

Observable.FromAsyncPattern<WebResponse>(
                            webRequest.BeginGetResponse,
                            webRequest.EndGetResponse)()
                            .SubscribeOn(Scheduler.NewThread)
                            .ObserveOn(Scheduler.Dispatcher)
                            .Subscribe(

The Rx design guidelines deem it as best practice to pass in the scheduler wherever appropriate, so that the concurrency is created in the right place to begin with. Now you know how to accomplish that.

We have touched on a couple of guidelines from The Rx Design Guidelines document in this section. There are many other suggestions for building robust, high-performing Rx.NET constructs in this document, so you are encouraged to study it in greater detail. In the next section of this chapter, you will continue practicing using Rx.NET by building a simple weather application, which will also allow us to discuss concepts such as error recover in Rx.NET.

Using Rx.NET with Web Services to Asynchronously Retrieve Weather Data

In this section, you will use a publicly available weather web service located at http://www.webservicex.net/WS/WSDetails.aspx?CATID=12&WSID=68 to retrieve and display current weather for a given ZIP code within the United States. In addition to weather services, there are many other useful web services available at this location, including ZIP code validation and currency conversion. As an exercise in the usage of Rx.NET, you are encouraged to build useful, functional applications that take advantage of these services.

From the development point of view, the weather application will consist of (1) asynchronously capturing user input (a ZIP code), and (2) asynchronously calling the web service and then displaying the current weather for a given ZIP code. Let's go ahead and create the application.

Creating a Windows Phone Project

First, you will create a new project, import all of the libraries, and create service references necessary to make the weather application work.

  1. Launch Visual Studio 2010 Express for Windows Phone and create a new Windows Phone Application project. Name it WeatherRx.

  2. In MainPage.xaml, change the name of the application to WeatherRx and change the page title to "Weather App" (you are also certainly welcome to name the application and the page according to your preference).

  3. Since you will be using Rx.NET to build this application, add a reference (by right-clicking and selecting Add Reference) to Microsoft.Phone.Reactive and System.Observable assemblies.

    You need to add a Service Reference to the weather service already mentioned. The weather service is an .asmx web service hosted at www.webservicex.net.

  4. To add a reference to this service, right-click the Project Name and select Add Service Reference. In the dialog that comes up, enter the following value in the Address Textbox: http://www.webservicex.net/WeatherForecast.asmx. Press the Go button.

  5. The WeatherForecast service should appear on the left. Click the arrow next to it, make sure to select WeatherForecastSoap service, and then rename the namespace to "svcWeather."

  6. Your final Add Service screen should look like Figure 18-9.

  7. Press the OK button.

Adding a Service Reference to the weather web service

Figure 18.9. Adding a Service Reference to the weather web service

Creating a User Interface

For the application, your goal is to create a screen that looks like the one shown in Figure 18-10. To assist in that objective, the XAML for visual elements that appear after the page title is pasted here. You can also copy and paste this XAML from the sample code available in the download section for this chapter.

  1. Open MainPage.xaml and add the following code:

    <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentGrid" Grid.Row="1">
                <TextBox Height="72" HorizontalAlignment="Left" Margin="0,51,0,0"
    Name="txtZipCode" Text="" VerticalAlignment="Top" Width="480" />
                <TextBlock Height="53" HorizontalAlignment="Left" Margin="6,13,0,0"
    Name="lblLegend" Text="Enter Zip Code Below for Current Weather" VerticalAlignment="Top"
    Width="462" />
                <TextBlock Height="30" HorizontalAlignment="Left" Margin="6,129,0,0"
    Name="lblWeatherFahrenheit" Text="Current Weather, Fahrenheit " VerticalAlignment="Top"
    Width="435" />
                <Image Height="150" HorizontalAlignment="Left" Margin="241,213,0,0"
    Name="imgWeather" Stretch="Fill" VerticalAlignment="Top" Width="200" />
        <TextBlock Height="30" HorizontalAlignment="Left" Margin="6,162,0,0"
    Name="lblCelsius" Text="Current Weather, Celsius" VerticalAlignment="Top" Width="435" />
        <TextBlock Height="30" Margin="6,379,39,0" Name="lblStatus" Text=""
    VerticalAlignment="Top" />
            </Grid>
        </Grid>

Notice how in addition to the textblocks that will hold the current weather information, the XAML also creates an image control that will show a visual representation of the current weather (e.g., sunny, raining, snowing, etc.). Notice also that the last </Grid> statement closes the LayoutGrid element, not shown in the preceding fragment.

WeatherRx design layout

Figure 18.10. WeatherRx design layout

Adding Logic to Get Weather Information

With design elements and proper references in place, you are ready to add code to the application. In this example, you will split the code into multiple functions for enhanced readability.

  1. Open MainPage.xaml.cs (by clicking MainPage.xaml and selecting View Code) and add the following using statements to the top of the page:

    using Microsoft.Phone.Reactive;
    using System.Windows.Media.Imaging;
  2. Add the following code after the InitializeComponent() statement of the MainPage() constructor:

    WireUpWeatherEvents();
    WireUpKeyEvents();

    Here, you are wiring up web service events and keystroke events in separate functions, a technique that will become very useful in the subsequent sections of this chapter when you deal with error recovery.

  3. Create the WireUpWeatherEvents function and its supporting GetWeatherSubject function by pasting the following code. Note how you have created a separate function (GetWeatherSubject) to return an Observable collection from the weather web service event.

    private void WireUpWeatherEvents()
                   {
                           var weather = GetWeatherSubject();
                   weather.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
                           {
                                   if (evt.EventArgs.Result.Details != null)
                                   {
                                   lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " +
                                   evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + "
                                   - " +
                                   evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();
    
                                   lblCelsius.Text = "Current Weather, Celsius: " +
                                   evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + "
                                   - " +
                                   evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();
    
                                   imgWeather.Source = new BitmapImage(new
                                   Uri(evt.EventArgs.Result.Details[0].WeatherImage,
                                   UriKind.Absolute));
                                   }
                     },
                   ex => { lblStatus.Text = "Sorry, we encountered a problem: " + ex.Message; }
                );
             }
    
         private IObservable<IEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>>
         GetWeatherSubject()
            {
                var weather =
    Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>(weatherClient,
    "GetWeatherByZipCodeCompleted");
                return weather;
            }
  4. Create the WireUpKeyEvents function that will define an Observable collection from the KeyUp events and create subscription to that collection by adding the following code:

    private void WireUpKeyEvents()
            {
            var keys = Observable.FromEvent<KeyEventArgs>(txtZipCode,
                    "KeyUp").Throttle(TimeSpan.FromSeconds(1)).DistinctUntilChanged();
            keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
                    {
                            if (txtZipCode.Text.Length >= 5)
                            {
    weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
                            }
                    });
            }
  5. Press F5 to run the application. You should see a screen prompting you to enter the US ZIP code to retrieve the current weather for. If you enter your ZIP code, you should get a reasonable estimate of your current weather, both on the Fahrenheit and Celsius scales. You should also see a small picture with a visual representation of the current weather conditions. Figure 18-11 shows sample output for the Jacksonville, FL area (ZIP code of 32202).

Let's spend some more time dissecting the tools you used to build this application. First, you used Rx.NET to create an Observable collection from the asynchronous responses to the weather web service calls. You used the following statement to create that collection:

var weather =
        Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>(weatherClient,
        "GetWeatherByZipCodeCompleted");

You then defined an Observer for this data source, so that when the data is pushed from the web service to Observers, you take action by displaying that data in the User Interface.

Next, you created an Observable collection of the KeyUp events in the txtZipCode text box and created an Observer for that collection. As a result, whenever users pause their typing for one second, the Observer on the keys data source will validate whether five or more digits have been entered in the Zip Code field. Then, it goes ahead and calls the function GetWeatherByZipCodeAsync, which in turn invokes an asynchronous request to the weather web service.

It's important to note the asynchronous nature of all these calls—if you had other functionality built into the application, you could continue using it while the asynchronous request completes. As stated several times, the asynchronous processing is an area that Rx.NET was specifically designed to address.

If you have done some form of asynchronous programming prior to Rx.NET, you can certainly appreciate that single code line. Prior to Rx.NET, in an asynchronous method design pattern in .NET, two methods were provided. The first method started the computation, and the second method acquired the results of the computation. If there was more than one asynchronous operation, even just the simple ones illustrated in the weather example, the management of those multiple methods quickly became a headache. The fact that Rx.NET also attempts to parallelize asynchronous requests across all available cores is a hefty bonus to an already generous benefits package of clarity and powerful querying of Observers.

Sample output of WeatherRx application for ZIP code 32202

Figure 18.11. Sample output of WeatherRx application for ZIP code 32202

Handling Errors in Rx.NET

In the world of asynchronous programming, and especially in the world of distributed asynchronous programming, errors are a fact of life and should be expected. Rx.NET Observers provide a separate OnError event handler to deal with unforeseen errors that may arise. For instance, to make the WeatherRx application more robust, let's add an OnError handler to the weather.Subscribe call. The resulting code would look like this:

weather.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
        {
                        if (evt.EventArgs.Result.Details != null)
                        {
                                lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " +
                                evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + "
                                - " +
                                evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();

                        lblCelsius.Text = "Current Weather, Celsius: " +
evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + "
                                - " +
                                evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();

                        imgWeather.Source = new BitmapImage(new
                                Uri(evt.EventArgs.Result.Details[0].WeatherImage,
                        UriKind.Absolute));
                        }
             },
         ex =>  {
                Deployment.Current.Dispatcher.BeginInvoke(() => lblStatus.Text = ex.Message);
                        }
         );

Note the somewhat cryptic (it's a lambda expression and it uses a lambda expression within its own body) use of the Deployment.Current.Dispatcher.BeginInvoke statement to get around cross-thread access issues discussed previously. In the preceding code, the OnError handler simply displays the exception text, but there is nothing stopping you from dissecting an error thoroughly and providing a possible corrective action. For instance, if the web service is not available at the address specified, you may retry your call to a different location of the web service. Rx.NET also has exception handling operators Catch, Finally, OnErrorResumeNext, and Retry, which aid in recovering from errors. You will explore some of them in the next section as we discuss some potential ways of handling intermittently available data connections on the phones.

Handling Data Connection Issues with Rx.NET

On a phone, slow or lost data connections are a fact of everyday life. Ideally, phone applications should detect such connections and provide a recovery mechanism to deal with them. Two potential ways to deal with slow or lost connectivity on the phone are: (1) let the user decide whether the application should retry what it was doing before the connection timed out or lost, and (2) provide an automated retry mechanism.

Rx.NET can aid in both scenarios. Furthermore, Rx.NET includes a special Timeout operation that will generate a timeout error if it does not receive data, such as a web service callback, from its Observable within a user-specified interval. Let's take a look at the Timeout operation in action. Let's change the WireUpWeatherEvents function to time out if it does not get any data for two seconds:

  1. Replace the WireUpEvents() function of the WeatherRx application with the following code:

    private void WireUpWeatherEvents()
    {
            var weather = GetWeatherSubject();
            weather.ObserveOn(Deployment.Current.Dispatcher)
                    .Timeout(TimeSpan.FromSeconds(2))
            .Subscribe(evt =>
            {
                    if (evt.EventArgs.Result.Details != null)
                    {
                    lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " +
                    evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + "
                    - " +
                    evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();
    lblCelsius.Text = "Current Weather, Celsius: " +
                    evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + "
                    - " +
                    evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();
    
                    imgWeather.Source = new BitmapImage(new
                    Uri(evt.EventArgs.Result.Details[0].WeatherImage,
                    UriKind.Absolute));
                    }
            },
            ex =>   {
                    Deployment.Current.Dispatcher.BeginInvoke(() => lblStatus.Text
                    = ex.Message);
                    }
            );
    }

    Now run the application and notice how after two seconds, it immediately times out and displays the timeout exception text on the emulator. What happened? You did not even get a chance to specify the ZIP code!

    Your code needs a little refactoring, or changing around. In the code so far, you subscribed to the web service's events immediately on application launch, and since you did not get any data two seconds after the launch of the application, that subscription timed out. The change that you need to make is to subscribe to the web service's events right before you invoke that web service, yet you have to be careful to create this subscription just once.

  2. Remove the call to WireUpWeatherEvents from the MainPage constructor and place it within the WireUpKeyEvents function, like so:

    private void WireUpKeyEvents()
            {
            var keys = Observable.FromEvent<KeyEventArgs>(txtZipCode,
            "KeyUp").Throttle(TimeSpan.FromSeconds(1)).DistinctUntilChanged();
                    keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
                    {
                            if (txtZipCode.Text.Length >= 5)
                            {
                                    WireUpWeatherEvents();
    
    weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
                            }
                    });
    }

    Now the timeout feature should work properly. Notice, however, that it will most likely take slightly more than two seconds to return a valid response from the Weather service.

    Rx.NET also provides a Retry method that optionally takes a parameter for the number of times to retry to re-subscribe to the Observable collection. If you don't specify that parameter, Rx.NET will try to re-subscribe to the Observable collection indefinitely. One way to deal with an absent or slow connection is to retry the subscription two or three times, and then, if unsuccessful, give the user the option to either retry once more or cancel. You will see how to give the user this option in the next section.

Revising WeatherRx to Manage Slow Data Connections

To modify the WeatherRx application, you will first add buttons to the UI to allow the user to either retry the failed connection or to exit gracefully. Then, you will add code to the application to react to the events on these new User Interface elements.

To add the new elements to the WeatherRx UI, do the following:

  1. Open MainPage.xaml and add two buttons right below the lblStatus textblock, as shown in Figure 18-12. Name the first button btnRetry and set its Content property to Retry. Name the second button btnQuit and set its Content property to Quit. Set the Visibility of both buttons to Collapsed.

    Weather application with error recovery elements

    Figure 18.12. Weather application with error recovery elements

    On retry, you will recreate the Observable connection to the weather web service, if it's needed, and then invoke the web service again.

  2. Double-click the Retry button and add the following handler code to the btnRetry_Click function:

    private void btnRetry_Click(object sender, RoutedEventArgs e)
    {
            btnQuit.Visibility = System.Windows.Visibility.Collapsed;
            btnRetry.Visibility = System.Windows.Visibility.Collapsed;
            lblStatus.Text = "";
    
            WireUpWeatherEvents();
            weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
    }

    If the user selects Quit, let's simply hide the buttons and the exception text.

  3. Double-click the Quit button and add the following code to the btnQuit_Click function:

    private void btnQuit_Click(object sender, RoutedEventArgs e)
    {
            btnQuit.Visibility = System.Windows.Visibility.Collapsed;
            btnRetry.Visibility = System.Windows.Visibility.Collapsed;
            lblStatus.Text = "";
    }

    Finally, you will need to ensure there is only one subscription to the weather web service at any given time.

  4. To ensure that there's only one subscription, first declare a module level variable by adding the following statement:

    IObservable<IEvent<GetWeatherByZipCodeCompletedEventArgs>> _weather;
  5. Next, change the GetWeatherSubject function to the following:

    private void GetWeatherSubject()
    {
            if (_weather == null)
            {
            _weather =
            Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>
            (weatherClient, "GetWeatherByZipCodeCompleted");
            }
    }
  6. Finally, change the WireUpWeatherEvents method to look like the following (notice how the timeout value is now set to a more reasonable five seconds as well):

    private void WireUpWeatherEvents()
        {
                GetWeatherSubject();
                _weather.ObserveOn(Deployment.Current.Dispatcher)
                .Timeout(TimeSpan.FromSeconds(5))
                .Subscribe(evt =>
                {
                        if (evt.EventArgs.Result.Details != null)
    {
                lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " +
                evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + " - " +
                evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();
    
                lblCelsius.Text = "Current Weather, Celsius: " +
                evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + " - " +
                evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();
    
                imgWeather.Source = new BitmapImage(new
                Uri(evt.EventArgs.Result.Details[0].WeatherImage, UriKind.Absolute));
            }
        },
        ex =>
        {
                Deployment.Current.Dispatcher.BeginInvoke(() => lblStatus.Text =
    ex.Message);
        Deployment.Current.Dispatcher.BeginInvoke(() =>
        btnQuit.Visibility=System.Windows.Visibility.Visible);
    
        Deployment.Current.Dispatcher.BeginInvoke(() => btnRetry.Visibility =
        System.Windows.Visibility.Visible);
        }
      );
    }

This example illustrates one approach to handling connection issues on Windows Phone 7 devices: you specify a timeout period, and if you don't get a response within that period, you prompt the user to retry or to quit.

Handling Multiple Concurrent Requests with Rx.NET

So far, the weather application that you have created is sending as many requests for weather data as the user types in ZIP codes. When the data comes back from the weather web service, the order that this data comes back in is not guaranteed. For example, if the user first types in 32207 (Jacksonville) and then types in 10001 (New York City), the weather results for Jacksonville may come in behind New York City, yet the user would not realize that she's seeing Jacksonville's weather when New York's ZIP code still remains on the screen. It would be great if there were a solution that gave an application the power to cancel out all weather requests that occurred prior to the latest one, i.e., in this example, a request for Jacksonville weather is canceled as soon as request for New York City weather is made.

Rx.NET provides such a solution. There are two operators in Rx.NET—TakeUntil() and Switch—that allow for cancellation of operations that occur prior to the latest operation and are still "in-flight," or are still pending the return values. Through the use of an elegant LINQ query, these operators tie together Observable collections, as you will see shortly. But first, there is some bad news: in the current implementation of .NET Framework on Windows Phone 7, it is impossible to link the beginning of the asynchronous SOAP web service invocation to the end of that invocation. The root of the problem is the exclusion of the CreateChannel method implementation in the Windows Communication Foundation libraries on Windows Phone 7. Microsoft had to slim down and optimize .NET Framework on the phone, and the loss of this method for the time being seems to be due to those optimization efforts.

Nevertheless, the technique for canceling in-flight requests still applies to the clients with full.NET Framework installed (Windows Forms and WPF applications) and to the Silverlight platform. For the weather application, you will "fake" the technique of canceling those requests by creating a new Observable collection for the weather service each time a user types in a new ZIP code. Note, however, that the Observable subscriptions that you will be creating listen for any completed weather service requests, and not the specific ones. In other words, your implementation of canceling in-flight requests on Windows Phone 7 is currently incomplete and not reliable. Here, each one of these subscriptions would process both Jacksonville and New York City weather from the example, and the order that this weather data comes in would be irrelevant. This is due to the aforementioned limitation in the current implementation of Windows Phone 7 framework—at present, you can't link the beginning of the SOAP web service call to the end of that service call on this platform.

To make the cancellation of operations on the Observable collections possible while those operations are in-flight, you will change the code around to expose Observable collections to LINQ queries.

Follow these steps to make operation cancellation possible:

  1. At the top of the MainPage class (right above the constructor), paste the following code to declare a module-level Observable collection for the KeyUp events of the ZIP code text box:

    IObservable<IEvent<KeyEventArgs>> _keys;
  2. Expose the Observables for both the KeyUp event of the ZIP code text box and for the web service callback by adding the following two methods to your code:

    private IObservable<IEvent<GetWeatherByZipCodeCompletedEventArgs>> GetWeatherSubject()
            {
            return
            Observable.FromEvent<svcWeather.GetWeatherByZipCodeCompletedEventArgs>(weather
            Client, "GetWeatherByZipCodeCompleted");
            }
    
            private void GetKeys()
            {
                    if (_keys == null)
                    {
            _keys = Observable.FromEvent<KeyEventArgs>(txtZipCode,
            "KeyUp").Throttle(TimeSpan.FromSeconds(1)).DistinctUntilChanged();
                    }
            }

The magic that makes the cancellations work appears in the next code snippet. Pay particularly close attention to the LINQ query; it establishes the relationship between the Observable collection for the KeyUp events and the Observable collection for the web service callbacks. Note that had Windows Phone 7 framework supported what is referred to as the Asynchronous pattern for web service calls (with the use of BeginXXX/EndXXX methods), you could have established a direct relationship between key sequences and web service invocations. However, with the following code, you have only a loose or indirect relationship between those two, since each subscription listens for any and all responses from the weather web service, and not just for specific ones. Right after the LINQ statement, there is a Switch() operator that instructs the application to dispose of the old subscription to the weather web service once there is a new key sequence awaiting in the _keys Observable collection.

  1. Add the following code to the application:

    private void WireUpWeatherEvents()
    {
                      GetKeys();
                      var latestWeather = (from term in _keys
                              select GetWeatherSubject()
                              .Finally(() =>
                              {
                      Deployment.Current.Dispatcher.BeginInvoke(() =>
                      Debug.WriteLine("Disposed of prior subscription"));
                              })
                      ).Switch();
    
                      latestWeather.ObserveOnDispatcher()
                              .Subscribe(evt =>
                              {
                                      if (evt.EventArgs.Result != null)
                                      {
                              lblWeatherFahrenheit.Text = "Current Weather, Fahrenheit: " +
                              evt.EventArgs.Result.Details[0].MinTemperatureF.ToString() + "
                              - " +
                              evt.EventArgs.Result.Details[0].MaxTemperatureF.ToString();
    
                              lblCelsius.Text = "Current Weather, Celsius: " +
                              evt.EventArgs.Result.Details[0].MinTemperatureC.ToString() + "
                              - " +
                              evt.EventArgs.Result.Details[0].MaxTemperatureC.ToString();
    
                              imgWeather.Source = new BitmapImage(new
                              Uri(evt.EventArgs.Result.Details[0].WeatherImage,
                              UriKind.Absolute));
                              }
                      },
                      ex => {
                                      Deployment.Current.Dispatcher.BeginInvoke(()
    =>lblStatus.Text = ex.Message);
                              }
                );
            }

Notice the .Finally statement in the code. Its purpose is to print a "Disposed of prior subscription" message into the Output windows when one Observable collection is being removed and replaced with the newer one. This occurs when there is a new event in the _keys module-level Observable collection.

Finally, you need to make some minor changes to the WireUpKeyEvents function, namely, the Observable sequence generation for the KeyUp event on the ZIP code has been moved into a separate GetKeys method.

  1. Replace the WiredUpKeyEvents() function with the following code:

    private void WireUpKeyEvents()
            {
                    GetKeys();
                    _keys.ObserveOn(Deployment.Current.Dispatcher).Subscribe(evt =>
                    {
                            if (txtZipCode.Text.Length >= 5)
    {
    
    weatherClient.GetWeatherByZipCodeAsync(txtZipCode.Text);
                            }
                    });
            }

    You are now ready to run the application.

  2. Press F5 and observe that the application behavior is virtually unchanged from the previous examples: you still type in the ZIP code and receive weather information for that ZIP code. However, behind the scenes, you will notice the messages printed in the Output window indicating that there are Observable sequences being disposed of in accordance to the new data (ZIP codes typed in) available in the key sequence observable collection.

Perhaps in the very near future, you will see a CreateChannel method available on the Windows Phone 7 platform. Once that happens, you could very easily enhance the previous example with the code linking the beginning and end of an asynchronous web service call through the Observable.FromAsyncPattern method. For right now, however, you can still take advantage of this extremely powerful feature of Rx.NET in Silverlight or on clients running the full version of .NET Framework.

Summary

This chapter provided a general overview of Reactive Extensions for .NET and their implementation of the Observer pattern. You built two applications that demonstrated the features of Rx.NET, including event representation as Observable data sources and seamless concurrent asynchronous processing and error handling. You learned about Marble Diagrams and some of the main design guidelines for building Rx.NET applications. You observed techniques for managing unreliable data links and the principles of cancellation of in-flight operations using the Rx.NET framework. As concurrent programming becomes more and more the norm, Rx.NET provides a powerful framework for asynchronous and parallel programming, including programming for the cloud. We have touched on the subject of Rx.NET lightly, but we hope that you have gained an appreciation for this technology and will take the initiative to learn (and, most importantly, practice!) Rx.NET development techniques on your own.

In the next and final chapter of this book, you will learn how to make your Windows Phone 7 applications more secure. You will learn about the common threats to mobile devices and the steps you must take to protect yourself and your customers from unwanted and potentially harmful attention.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.167.114