bling.github.io

This blog has relocated to bling.github.io.
Showing posts with label Rx. Show all posts
Showing posts with label Rx. Show all posts

Thursday, September 29, 2011

Push Driven Development with Reactive Extensions


This is going to be the last post that concludes my series on building a real-time push app with Silverlight.  Any additional posts would likely be outside the context of writing a push app and more about how I’m adding features to ping.pong, my Twitter app, so I think this is a good place to wrap up and talk generally from a top down overview of building a push-style application.

Here’s a recap of everything discussed so far:

Part 1:  Basics – Creating an Observable around a basic HTTP web stream against Twitter’s streaming API

Part 2:  Subscription and Observation of Observables

Part 3:  Basics of UX design with a look at shadows and gradients.

Part 4:  Integrating with 3rd party libraries, notably Caliburn Micro and Linq2Twitter and how to achieve polling with observables.

Part 5:  A minor hick up with Linq2Twitter.

Part 6:  Taking advantage of transparencies to improve the design and reusability of UX.

Part 7:  A summary of all things encountered so far, replacing Linq2Twitter with Hammock, first release of code to GitHub, and a binary released capable pulling and streaming tweets from Twitter.

Part 8:  Examples of using Caliburn Micro to easily resolve data bindings that otherwise would be much more effort.

And that leads us to this post…

PDD (Push Driven Development)

One of the main goals of this series is to create a performant Silverlight app based on push principles, as opposed to more traditional pull principles.  To that effect, ping.pong has performed remarkably well and is limited only by Twitter’s throttling, which currently appears to be maximum of 50 tweets per second via the streaming API.

Writing the application from a push-driven mindset was definitely unintuitive at first, and I had to refactor (actually rewrite is more accurate) the code many times to move closer to a world where the application is simply reacting to events thrown at it (as opposed to asking the world for events).

To be absolutely clear on what I mean on the differences between push and pull, here’s a comparison:

Pulling Push
var e = tweets.GetEnumerator();
while (e.MoveNext()) // is there more?
{
  e.Current; // get current
  DoSomething(e.Current);
}
IObservable<Data> data = /* get source */

// whenever data comes, do something
data.Subscribe(DoSometing);

On the pulling side, the caller is much more concerned with the logic on how to process each message.  It needs to repeatedly ask the world, “hey, is there more data?”.

On the push side, the caller merely asks the world, “hey, give me data when you get some”.

Twitter is a perfect example because their APIs have both a pulling and pushing models.  Traditional clients poll continuously all the time, and many had configurable options to try to stay under the 200 API calls per hour limit.  Most of Twitter’s API still consists of pulling, but the user’s home line and searching can be streamed in near real time via the streaming API, aka. push.  Streaming tweets effectively removes the API call limit.

Push and Pull with Reactive Extensions

The beauty of Rx is that regardless of whether it is actually pushing or pulling, the API will look same:

IObservable<Tweet> tweets = _client.GetHomeTimeline();
tweets.Subscribe(t => { /* do something with the tweet */ });

As far as the caller is concerned, it doesn’t care (or needs to know) whether the GetHomeTimeline method is polling Twitter or streaming from Twitter.  All it needs to know is when a tweet comes it will react and do something in the Subscribe action.

In fact, Subscribe simply means “when you have data, call this”, but that could also be immediately, which would be analogous to IEnumerable.

However, if that was the only thing Rx provided it wouldn’t be as popular as it is, because other pub/sub solutions like the EventAggregator already provide a viable asynchronous solution.

Unlocking Rx’s power comes with its multitude of operators.  Here’s an example:

public static IObservable<Tweet> GetStreamingStatuses(this TwitterClient client)
{
  return client.GetHomeTimeline()
      .Merge(client.GetMentions())
      .Concat(client.GetStreamingHomeline());
}

GetHomeTimeline and GetMentions initiate once-only pull style API calls, while GetStreamingHomeline will initiate a sticky connection and stream subsequent tweets down the pipe.

The Merge operator is defined as this: “Merges an observable sequence of observable sequences into an observable sequence.”

I think a better description would be “whenever there is data from any of the sources, push it through”.  In the example above, this would translate to whenever a tweet comes from either the home timeline or the mentions timeline, give me a Tweet (first-come-first-push), followed by anything from the streaming timeline.

And there lies one of the greatest beauties of Rx.  All of the complexity lies solely on setting up the stream and operators.  And that, also, is its disadvantage.

Rx Complexity

Let’s take a look at the Concat operator, defined as: “Concatenates two observable sequences.”  In the remarks sections it states this: “The Concat operator runs the first sequence to completion. Then, the second sequence is run to completion effectively concatenating the second sequence to the end of the first sequence.”

Let’s try it out:

var a = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => x.ToString());
var b = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => "s" + x);
a.Concat(b).Subscribe(Console.WriteLine);
// output: 0, 1, 2, 3, 4...

As expected, only numbers are printed because the first sequence never ends, so it won’t concatenate the second one.  Let’s modify it so that it does finish:

int count = 0;
var a = Observable.Interval(TimeSpan.FromSeconds(1))
    .TakeWhile(_ => ++count < 5)
    .Select(x => x.ToString());

Note, that using Observable.Generate is preferred because it doesn’t introduce an external variable, but I stuck with Interval so the code looks similar to the second observable.  As expected again, it will print “0, 1, 2, s0, s1, s2”.

OK, let’s spice things up.  Let’s make b a ConnectableObservable by using the Publish operator, and immediately call Connect.

int count = 0;
var a = Observable.Interval(TimeSpan.FromSeconds(1))
    .TakeWhile(_ => ++count < 5)
    .Select(x => x.ToString());
var b = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => "s" + _).Publish();
b.Connect();
a.Concat(b).Subscribe(Console.WriteLine);

What do you think the output of this will be?  The answer is “0, 1, 2, 3, s5, s6, s7, …”

Despite using the same Concat operator, the result can be very different depending on the source observables.  If you use the Replay operator, it would have printed “0, 1, 2, 3, s0, s1, s2, …”

Years and years of working in synchronous programming models have trained us to think in synchronous ways, and I picked Concat specifically because Concat also exists in the enumerable world.  Observable sequences are asynchronous, so we never know exactly when data comes at us, only what to do when it does.  And because streams occur at different times, when you combine them together there are many many ways of doing so (CombineLatest, Merge, Zip, are just a few).

The greatest hurdle to working in Rx is to know what the different combinations do.  This takes time and practice.  RxTools is a great learning tool to test out what all the operators do.

Unit Testing

Last but not least, Rx can make it easier to write unit tests.  The concept is easy: take some inputs and test the output.  In practice this is complicated because applications typically carry a lot of state with them.  Even with dependency injection and mocking frameworks I’ve seen a lot of code where for every assert there is 10 lines of mock setup code.

So how does it make it easier to test?  It reduces what you need to test to a single method, Subscribe, which takes one input, an IObservable<T>.

Conclusion

Rx is a library unlike any other you will use.  With other libraries, you will add them to your solution, use a method here or there, and go on with your life.  With Rx, it will radically change the way you code and think in general.  It’s awesome.

Friday, September 16, 2011

Building a Real-time Push App with Silverlight: Part 7

Infrastructure Refactor

A lot of things changed internally, and I mean….a lot….

From an infrastructure standpoint, I decided to remove the dependency on LinqToTwitter, and I replaced it with Hammock.  A couple things led me to this decision, one being the Silverlight support wasn’t as good as I’d hoped, and the streaming API implementation was limited.  After reading the Twitter documentation I realized that the REST API was super simple and I’d be better off writing a simple interface to it.

I heard good things about Hammock, so I decided to give that one a try (I wasn’t going to go as far as reimplementing OAuth).  It was pretty easy to set up and in the end I was able to get Twitter working again and with less lines of code compared to the beginning of the refactor.

Goals

I had a couple goals for this project:

  • Learn:  I was a complete newbie to Reactive Extensions when I started but now I understand it enough to hit the ground running with it.  I’m still learning about more conventions available to Caliburn.Micro.
  • UX:  I wanted to learn a little more about interface design.  I wanted to know how little changes to gradients, shadows, colors, etc. could have a radically effect in the end result.
  • Performance:  It should be fast.  It should be able to react to real-time data.  And it should do it with low CPU utilization.
  • Concise:  I am a huge advocate for KISS.  I like convention over configuration.  I like implementing something in 2 lines of code rather than 20 (assuming it’s not cryptic).  As I was writing the app and refactoring, if there was an opportunity to remove a line of code, I did it.  The result is that the app currently consists of less than 500 lines of code as of this post (excluding XAML).

Tidbits

What are some interest things I learned?

  • System.Json is an amazing assembly.  All you need to do is invoke JsonValue.Parse on a string and it will create a JsonValue for you, which will be a dictionary of key/value pairs.  What’s more, by doing something like “string s = json[“text”]” will do an explicit conversion and unescape JSON characters, and only via the explicit operator.  Calling ToString(), even though converting it to a string, will not unescape.  This was completely undocumented and only found when I looked at the source code via Resharper’s external sources feature.
  • Rx is awesome.  When I ran into performance problems of trying to stream tweets from the world that contained the letter ‘a’ all I had to do was add an operator to improve the performance (in this case it was Buffer).  It should be noted that it is very important to understand what Rx is doing underneath the hood to realize its benefits.  Rx lets you refactor 30 lines of async code into 1 operator, but it’s still doing that 30 lines of code – you just don’t see it.
  • I really, really, like the conventions available from Caliburn.  Some of the features that come out of the box from this very small library saves me from writing a lot of boilerplate code like commands, triggers, and evening bindings (Caliburn will auto bind x:Name to a property).
  • Twitter’s documentation for user streams currently sucks and some trial and error was required to get it working.

What is the end result of all this effort?  We have a styled Twitter app that can update your status, pull your home/mentions timeline, and most importantly will stream all subsequent tweets.  There’s no pulling and no limits.  You will get a tweet of everyone you follow in real-time as it happens.

Moreover, there’s a feature to connect to the Streaming API to search Twitter for anything.  To get an idea of what we’re talking about, here’s a full screenshot of it:

image

You read that right.  I’m streaming any tweet in the world that has the words ‘and’, ‘the’, ‘yes’, or ‘no’ in them.  This is streaming around 400kB/s continuously and CPU utilization is under 25%.  The tweets are coming so fast it’s impossible to read them (at a rate of 50 tweets/second), so ideally you’d want to specify realistic search terms.

Moreover, the majority of the performance cost is actually downloading all the profile images.  If I take took out pictures I could stream any tweet in the world that has the letter ‘e’ in it at under 10% CPU.  It looks like Twitter limits the rate of tweets to 50 tweets/second because that was the rate for this one as well.

Features are minimalistic.  You can update your status, but you can’t DM, you can’t RT, you can’t do any of the normal things.  My original goal was not to write another Twitter client, but it’s actually quite fun to do so, so I’ll probably eventually get all features in.

And as promised, it’s up on GitHub, and version 0.0.0.1 alpha (yes! expect bugs!!) is available in the downloads section.  Or, here’s a direct link to the XAP file on my Dropbox.  Have fun!

Monday, September 5, 2011

Building a Real-time Push App with Silverlight: Part 4

Originally I wanted to avoid bringing in external libraries to keep the app as lean as possible, but then I realized that I would spend too much time reinventing the wheel.  Twitter is deprecating basic authentication in the near future, which makes OAuth no longer optional.  Rather than writing yet another Twitter client (if you’re curious I found a great reference here), I fired up NuGet and brought in LinqToTwitter, and while I’m there I brought in Autofac and Caliburn.Micro as well.

Naturally, LinqToTwitter will work nicely with Rx because as name implies it uses LINQ heavily.  Caliburn.Micro is a MVVM library which I’ve always wanted an excuse to try because of features like this:

<ListBox cal:Message.Attach="[Event Loaded] = [LoadList($dataContext)]" />

That’s only scratching the surface of what Caliburn can do, so it will be a fresh breath of air to see what else it can do.

By default, Caliburn uses MEF to wire up its bootstrapper.  After adding a couple [Import]s and [Export]s, I knew it wasn’t for me.  It works well for writing plugins, i.e. external dependencies because of its built-in assembly scanning capabilities, but for injecting internal dependencies, other IoC containers do a much better job of that.  I used Castle Windsor in past projects, but for a change I’m going to use Autofac which I haven’t used since v2 came out.

When this was all said and done the View was the only thing that didn’t change.  Everything underneath either changed radically or was deleted altogether (because LinqToTwitter provided it).  I added OAuth support and registered my application with Twitter, and with that was the birth of Ping Pong.

This took much longer than expected.  Silverlight 5 RC just came out and it broke pretty much any container (including MEF) for OOB because of a TypeLoadException.  I haven’t been using too many v5 features, so for the time being I downgraded to v4 to get the project working until RC2 comes out.

Integrating LinqToTwitter was a challenge.  The project site has a lot of good documentation, but most of it was for desktop, not Silverlight, and because of that I banged my head a couple times.  I wish I grabbed the source code earlier because it’s there where you’ll find hundreds of working examples (in code!) to do everything with the library (and in Silverlight).

After all that, PingPong now has 3 columns (home, public, sampling) that dynamically resizes (it’s surprising that MetroTwit is the only client that does this….) to the window size.

image

Oh, and there’s pictures now!  The streaming time line takes significantly more CPU now that it has to load images, but we’re still sitting at around 5-10% for what is continuously streaming data and loading pictures.  Not too shabby!  (It took a couple tries to get a PG-13 screenshot from the public/streaming time lines…)

To conclude this post in the series, I’m going to talk about converting an asynchronous operation into an Observable that does not follow any predefined pattern.

Creating an Observable

One of Silverlight’s limitations is that almost everything needs to be an asynchronous call.  In regards to LinqToTwitter, something like this will fail (but work on desktop):

var tweets = (from t in context.Status
              where t.Type == StatusType.Public
              select t).ToArray();

On Silverlight you will get a single empty element.  To get it working, there is an extension method that comes with the library, and you use it like this:

(from t in context.Status
 where t.Type == StatusType.Public
 select t)
  .AsyncCallback(tweets => { /* do something with it */ })
  .FirstOrDefault();

Code is self-explanatory.  The FirstOrDefault() exists only to initiate the expression, otherwise it wouldn’t do anything.  So now the question is how do we convert that into an Rx Observable?

Every time I write an Rx query I try to use the least amount of state as possible.  This helps to keep the number unexpected anomalies to a minimum.  In the following section of code, I was able to get it down to 2 fields: _sinceId, and Context.  There is probably some operator that will let me save the sinceId variable from one observable to the next but I wasn’t able to figure it out.  In any case, I came up with this:

_subscription =
    Observable.Create<Tweet>(
        ob => Observable.Interval(TimeSpan.FromSeconds(60))
                  .StartWith(-1)
                  .SubscribeOnThreadPool()
                  .Subscribe(_ =>
                  {
                      ulong sinceId;
                      (ulong.TryParse(_sinceId, out sinceId)
                           ? Context.Status.Where(s => s.Type == statusType && s.Count == 200)
                           : Context.Status.Where(s => s.Type == statusType && s.Count == 200 && s.SinceID == sinceId))
                          .AsyncCallback(statuses =>
                          {
                              foreach (var status in statuses)
                              {
                                  ob.OnNext(new Tweet(status));
                                  _sinceId = status.StatusID;
                              }
                          })
                          .FirstOrDefault(); // materalize the results
                  }))
        .DispatcherSubscribe(SubscribeToTweet);

That contains some custom code:

  • Context:  is a TwitterContext from LinqToTwitter
  • DispatcherSubscribe:  is a helper extension method which Subscribes on the ThreadPool, Observes on the Dispatcher, and then Subscribes with the specified action
  • SubscribeToTweet: a method in the base class which adds to a ObservableCollection so the UI gets updated

To translate the code, here is a basic flow of what’s happening:

  1. Observable.Create wraps the subscription of another Observable.  It provides access to an IObserver ob which lets you explicitly invoke OnNext().
  2. Observable.Interval will raise an observable every 60 seconds.
  3. The subscription of Observable.Interval will query the TwitterContext for the next set of tweets.
  4. Inside the AsyncCallback, it invokes ob.OnNext as well as keeps track of the ID so the next time it queries it only gets newer tweets.
  5. Finally, DispatcherSubscribe will take the Tweet object and add it to an ObservableCollection<Tweet>, which notifies the UI.

As always, you should “clean up your garbage”.  In this respect I was pretty impressed with Rx as it was able to clean up the entire chain of observables with a single call to _subscription.Dispose().  Nice!

In the next post I’m going to switch back to UI and completely restyle the application.  The code will hit GitHub soon as well (I promise!).  Stay tuned…

Sunday, August 28, 2011

Building a Real-time Push App with Silverlight: Part 3

In this part we’re going to fire up Expression Blend (the trial for version 5 can be found here) and do some UI work.

In part 2, I created a simple Twitter client which connected to the streaming API, and connected to the sampling request which brings back random tweets.  Here is the data template:

<DataTemplate x:Key="TweetDataTemplate">
    <Grid DataContext="{Binding}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock FontFamily="{StaticResource FontFamily}" FontSize="12" Text="{Binding Text}" TextWrapping="Wrap" />
        <TextBlock Grid.Row="1"
                   HorizontalAlignment="Right"
                   VerticalAlignment="Bottom"
                   FontFamily="{StaticResource FontFamily}"
                   FontSize="13.333"
                   Foreground="BlueViolet"
                   Text="{Binding ScreenName}" />
        <TextBlock Grid.Row="1"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Bottom"
                   FontFamily="{StaticResource FontFamily}"
                   FontSize="9.333"
                   Foreground="DarkCyan"
                   Text="{Binding CreatedAt}" />
    </Grid>
</DataTemplate>

This renders into something like this:

image

The text is randomly generated from Blend’s sample data capability, which is totally awesome as it allows designers to see what they’re working with, and keeps the sample data separate from the real data.

While design is a matter of personal taste, and you’re bound to get disagreements between different people, if you follow some basic rules you’ll satisfy a greater audience.

  • Subtle gradients and small shadows
    • If you take a look at all the nice interfaces, they tend to use very slight gradients and small shadows.  Most of the time you don’t even notice unless you look closely.
    • I think Microsoft’s Metro design is beautiful.  Reason?  It emphasizes text over decorations (like gradients and shadows).  This tends to lead to very clean design because there’s very little opportunity to abuse gradients and shadows.
  • Realism and light sources
    • Continuing on with gradients and shadows, they should be realistic.  Look at your design from a 3D point of view.  Apply a light source from a certain angle, and then apply your shadows relative to that light source.
    • Convey distance properly
      • Darker shadows imply being closer to the background, whereas lighter shadows imply being further away.  Use blurring to add emphasis to the distance.
        image
      • If you overlap planes you should apply these rules to each individual plane.  Don’t use the same border for everything.  Think about how it would look like in real life if you laid it out like that with pieces of paper.  The shadow sizes for that will be different, so you should do the same.
      • Also keep in mind that the shadows used above are way too much for any application.  Be subtle!
  • Consistent theme
    • This one seems obvious but nothing is worse than having a nice looking application bring up an unskinned dialog.
  • Usability
    • If the design doesn’t serve a purpose to make it more usable, it shouldn’t be there.  Even something as simple as black on white follows this – you do that so you can read text.  However, even something as simple as that can be improved.  Take a look at why the Kindle is so successful.  The readability is better because of the lower contrast between the black and light-brown background.

With these starting points, let’s redesign the data template.

<DataTemplate x:Key="TweetDataTemplate">
   <Grid>
       <Grid.Background>
           <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
               <GradientStop Color="#FFDADADA" />
               <GradientStop Offset="1" Color="#FFC8C8C8" />
           </LinearGradientBrush>
       </Grid.Background>
       <Grid.RowDefinitions>
           <RowDefinition />
           <RowDefinition Height="Auto" />
       </Grid.RowDefinitions>
       <TextBlock FontFamily="{StaticResource FontFamily}" FontSize="12" Text="{Binding Text}" TextWrapping="Wrap" />
       <TextBlock Grid.Row="1"
                  HorizontalAlignment="Right"
                  VerticalAlignment="Bottom"
                  FontFamily="{StaticResource FontFamily}"
                  FontSize="13.333"
                  Foreground="BlueViolet"
                  Text="{Binding ScreenName}" />
       <TextBlock Grid.Row="1"
                  HorizontalAlignment="Left"
                  VerticalAlignment="Bottom"
                  FontFamily="{StaticResource FontFamily}"
                  FontSize="9.333"
                  Foreground="#FF003D8F"
                  Text="{Binding CreatedAt}" />
       <Border Grid.RowSpan="2" BorderBrush="#FF999999" BorderThickness="0,0,0,1" />
       <Border Grid.RowSpan="2" BorderBrush="White" BorderThickness="0,1,0,0" />
   </Grid>
</DataTemplate>

After these changes, it looks like this:

image

Did you notice the gradient?  You might think after seeing it here to adjust the gradients more so you can see it.  That would be a mistake.  See below.

 

 

image

To the right is the exact same thing, but stacked vertically three times.  When this happens the subtle difference between the top and bottom of the control is more pronounced, so it looks like multiple panels are aligned together.image

 

 

 

 

However, there’s still a little touch you can add.  The white and gray borders are only 1 pixel high, but that’s the little touch needed to make it look crisp.

 

 

 

 

Finally, let’s see the before and after (or eh…rather after and before, because I took the screenshot backwards :P):

image

Saturday, August 27, 2011

Building a Real-time Push App with Silverlight: Part 2

Let’s review the main Rx code from last time:

public IObservable<string> GetJsonStreams()
{
  var request = GetRequest();
  return Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)()
    .Select(wr => wr.GetResponseStream())
    .Select(str => Observable.FromAsyncPattern<byte[], int, int, int>(str.BeginRead, str.EndRead))
    .SelectMany(ParseJson);
}

One thing I didn’t like about this was that the web request object was created regardless of whether the Observable gets a subscription or not.  This is potentially wasted resources, and I wanted to refactor this to be completely lazy.

And with this I started to run into my first “huh?” moments with Rx: I blocked the UI thread.  How did I do that?  I started down the path of exploring some more of the Rx methods, which lead me to Create, which lets you manually call OnNext.  With this train of thought, I came up with something like this:

return Observable.Create<string>(obs =>
{
  var request = GetRequest();
  var response = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)().First();
  var str = response.GetResponseStream();
  var reader = Observable.FromAsyncPattern<byte[], int, int, int>(str.BeginRead, str.EndRead);
  foreach (var json in ParseJson(reader))
      obs.OnNext(json);
 
  obs.OnCompleted();
  return str;
});

Great!  The initialization of the web request only occurs when subscribed!  And it will even dispose the stream (by returning str) upon unsubscription.  I ran the app and the UI thread immediately blocked.  What happened?

Rx has the concept of subscription and observation, and provides a way to subscribe and observe on different threads.  Here is the original code that subscribed:

s.GetJsonStreams()
   .ObserveOnDispatcher()
   .Subscribe(x => Text = x);

Can you spot the error?  I explicitly told Rx to observe on the dispatcher thread, because I want the action inside Subscribe to be invoked on the UI thread, but I didn’t specify where I want to set up the subscription.  Since I left it out, it uses the current thread, which happens to be the UI thread.  To solve this, it’s as simple as doing this:

s.GetJsonStreams()
  .SubscribeOn(Scheduler.ThreadPool)
  .ObserveOnDispatcher()
  .Subscribe(x => Text = x);

That’s it!  Easy!  This also follows one of the most important guidelines when using Rx: Subscription and Observation should be done as late as possible, typically just before the Subscribe.  Anything more and you’ll likely make Rx spawn more threads than are necessary or some other nasty bugs.  KISS!

Now with that out of the way, let’s replace the boring TextBlock with something more usable.  First, I need to parse all the JSON streams I’m getting into bindable models.  To do that, I upgraded my StreamReader component and threw in System.Json for some basic parsing:

public class TweetParser
{
    private int _stack;
    private readonly StringBuilder _sb = new StringBuilder();
 
    public IEnumerable<Tweet> Parse(byte[] buffer, int count)
    {
        for (int i = 0; i < count; i++)
        {
            var current = (char)buffer[i];
            _sb.Append(current);
 
            if (current == '{') _stack++;
            else if (current == '}') _stack--;
 
            if (_stack == 0 && _sb.Length > 0)
            {
                Tweet tweet;
                var value = JsonValue.Parse(_sb.ToString());
 
                if (value is JsonObject && Tweet.TryParse((JsonObject)value, out tweet))
                    yield return tweet;
 
                _sb.Clear();
            }
        }
    }
}

Nothing overly complicated.  Next, the Tweet object:

public class Tweet
{
    private readonly JsonObject _json;
 
    public static bool TryParse(JsonObject value, out Tweet tweet)
    {
        if (value.ContainsKey("text") && value.ContainsKey("user"))
        {
            tweet = new Tweet(value);
            return true;
        }
        tweet = null;
        return false;
    }
 
    private Tweet(JsonObject json)
    {
        _json = json;
    }
 
    public string Text
    {
        get { return _json["text"].ToValueString(); }
    }
 
    public string ScreenName
    {
        get { return _json["user"]["screen_name"].ToValueString(); }
    }
}
 
internal static class TweetEx
{
    public static string ToValueString(this JsonValue s)
    {
        return s.ToString().Trim('"');
    }
}

To keep things simple I’m only extracting the screen name and text.  I won’t bore you setting up the views since it’s just simple ListBox bound to an ObservableCollection<Tweet>, and a DataTemplate for Tweet.  When it’s all said and done, we see something like this:

image

Performance is still good at 2-5% CPU, even though we’re scrolling through 1000 items in near real-time.

Stay tuned for part 3, when we introduce Expression Blend and go into basics of UI design.  Also, most of this will hit GitHub very soon.