Tuesday, November 27, 2012

Dogfooding Windows 8: I Tell All

The other day I read an article about Windows 8 and “six long-term Windows 8 users tell all.” The premise? Several columnists over at ZDNet had been using Windows 8 for quite some time, and were interviewed about the experience. You can read about the results in the original article. I am also a writer. In addition, I sling code and manage software projects. I’ve also been “dogfooding” Windows 8 since I could first get my hands on it, so I thought it might be interesting to compare my own experience.

The first part of the article summarized the questions at a high level. If you want to use that chart to compare to my answers, I have them here in bullet form:

  • How much have you used Windows 8? 14 months.
  • Use Metro vs. Desktop? Both.
  • Using Modern UI apps? Internet Explorer, People, Calendar, Weather, Skype, TweetRo, Bing, Google Search, Netflix, iHeartRadio, Bank of America, Kayak, Nextgen Reader, Music, Video, Flow Free, Pew Pew, Mahjong Deluxe, Card Games Chest, NASA Be a Martian, Dictionary.com, Lync, //BUILD
  • Miss or replaced the classic Start menu? Don’t miss it a bit.
  • Tweaked Windows 8? Not really.
  • Using touch hardware? Yes and no (used it both laptop without touch, and slate with)
  • Which OS to install on a new machine? Windows 8.
  • Prefer Win7 or Win8? Windows 8.

While the questions didn’t ask specifically about desktop, it’s important to make this note: I wrote the first five chapters of my book Building Windows 8 Apps with C# and XAML on a Samsung Series 7 Slate (then switched to a laptop when I finally upgraded that from Windows 7). I also used it to develop the sample applications for the book. In addition, I use the slate to carry around the house and as you can see, am quite a “power user” of the Windows Store apps, so I believe I can speak from hands-on experience. I am also very aware I am a developer, so my view/opinion and approach will not translate well to an “average consumer.”

Here is the detailed list of questions and my answers:

Question #1: How long have you been using Windows 8 (and previews) for day-to-day desktop use?

I pitched my Windows 8 book right as //BUILD happened in September 2011. I downloaded the Developer Preview the night it was released, then used my slate as the means to develop applications and write the first several chapters. Once the Consumer Preview came out, I switched to a dual boot on my main laptop and finally upgraded wholesale to Windows 8 when it went RTM.

Question #2: Do you use the Metro [sic] tile interface, or live completely in the desktop?

I live and switch easily between both. On my laptop, I’m mostly in the desktop interface, with a twist. I use the Skype app to make phone calls. I have an interesting set-up because I use a Kinect sensor for my audio. The audio array is phenomenal and most people tell me I sound like I’m on a headset even though I’m using the sensor “hands free.” When I dial the call, I move Skype into snapped mode. This allows me to have two screens for my desktop (one full screen and most of the second) with a small strip to monitor my call, mute when necessary, or respond to messages.

At the same time, my tablet is always next to me as a “third screen.” I often use the TweetRo app to display the “signal” group I’ve made (a filter for people who don’t add a lot of noise to their timeline). It will auto-refresh so I can always stay up to date on the stock-ticker that is social networking while I’m working. On the slate, I’m almost always in the Modern UI interface and that’s as it should be (do you see what I did there, fixing the terminology in the answer?) I still fallback to desktop mode for the Office suite of tools and for occasional development.

Question #3: Are you using relying [sic] on any Modern UI apps for day-to-day use? Which ones?

That would be an empathetic, “yes.” I use Internet Explorer and the Calendar quite a bit, as well as Skype and Lync. I use Skype to make most of my calls and Lync is what our company uses for group meetings and screen sharing. I use the Modern UI for both. What you might find more interesting is how I keep up to date with news. I have a ton of feeds and alerts set up in Google Reader. I love the Nextgen Reader app for browsing and reading news stories. When I’m in “reading mode” though I’m not necessarily into tweeting mode, so I have a simple system for synchronizing between my slate and laptop. On the slate, I browse the stories in the reader and if I’m interested in exploring further or want to share the item, I’ll star it. On the laptop, I can use the web interface to pull starred items and use that view to compose my tweets.

The Bank of America app keeps me from having to drive to an ATM or local bank. When I have a check to deposit, I go into the app, take a picture of the front and back of the check, and there it is – deposited. When the girls are watching a show I’m not interested in on the big TV, a set of headphones and my slate lets me watch my own Netflix movies without disturbing them. The games are great for killing time in the airport, and the radio and music apps I use whenever I’m hanging out on the deck or just relaxing and want some music. Yes, I’m a power user of the Windows Store apps.

Question #4: Do you miss the Start menu or have you replaced it?

No, I don’t miss it. About the only thing I ever used it for was the search feature, and that hasn’t gone anywhere. I never liked having to find a folder and drill down and click on something to open an app. I far prefer tapping the Windows Key, starting to type part of a program name, then hitting the Enter key and launching it. I can get to any app lightning fast. Are there icons it would be easier to click on? Sure. For those, I pin them to the taskbar. I have a big monitor, so my taskbar has lots of icons. Honestly I think if I used more than I have space for, I’d have bigger issues than worrying about where the start menu went. If you’re curious, here’s my taskbar-pinned apps that I can launch with a tap or click:

  • Internet Explorer
  • File Explorer
  • Visual Studio 2012
  • Blend 2012
  • Developer Command Prompt
  • Google Reader (web link)
  • FireFox
  • Chrome
  • Fiddler
  • GMail (web link)
  • Hyper-V MMC Snap-in (for those customers I have to run Windows 7 for)
  • Office 365 Web Link
  • LinqPad
  • IETester (for those customers I need to test IE7+)
  • Balsamiq
  • Outlook
  • Lync
  • LiveWriter (for writing what you’re reading right now)

Question #5: How have you tweaked your environment for day-to-day productive use of Windows 8 (add-ons, settings, etc.)?

I really haven’t done much tweaking at all. I make sure I have roaming enabled, so it’s always fun when I install Windows 8 on a new machine, log in, and suddenly see a Commodore 64 BASIC prompt waiting for me (that’s my lock screen of choice, and it confuses enough people I don’t see myself changing it any time soon). The only other tweak has really just been pinning some items to the taskbar for ease of launching from the desktop interface, and I constantly rearrange tiles based on which ones are live and static, what their functionality is and how often I use them.

Question #6: Have you added any touch hardware (like a touch mouse or trackpad)? Do you find that improves productivity or just simply makes Windows 8 usable?

I haven’t added any touch hardware other than what comes “as is.” Before Windows 8, I did quite a bit of slate development so one of my two monitors is touch-enabled. Sometimes it’s fun to use touch (for example, when I run the Windows Store Skype app and it shows me that big Modern UI dial pad, I just have to use it instead of the numeric keypad on my keyboard) but otherwise I use what I’ve got. My biggest secret has been learning all of the Windows 8 shortcut keys that make it easy to open the Charms bar, search, swap primary monitors, etc. on the laptop, then using all of the touch gestures on my slate.

Question #7: So you’re going to go out and buy your new, hot primary work machine. Would you put Windows 7 or Windows 8 on it, and why?

Hands down Windows 8. No doubt in my mind. There are a million enhancements to the desktop that I just can’t live without now. On top of faster boot, stable sleep and resume, native mounting of ISO and VHD images, USB 3.0 support, etc., I actually do enjoy the Modern UI and the apps that run on it. I don’t want you to think it’s all wonderful. There are certainly some nasty quirks like clicking a mail link in Outlook only to have it pop open the Windows Store Mail app, but those are few and far between for me. In the case of customers who don’t support Windows 8 (mostly from a security perspective, so the VPN access policy for example might reject a connection from a Windows 8 host) I use the built-in Hyper-V and run a Windows 7 image. It works great. I’m talking a huge enterprise web solution with dozens of projects and I work, compile, build, deploy and test without any problems on the VM. Better yet, the newer machines are optimized for Windows 8 and come with SSD drives. Windows 8 + SSD = killer productivity combo.

Last question [or question #8]: do you prefer Windows 7 or Windows 8?

What do you think? Windows 8. I get everything I had in Windows 7 (I’ve read some of the amusing articles saying it should be called “Window” because the Windows don’t overlap, and that’s simply not true – I get full overlapped, multi-tasking goodness on the desktop) plus the new features of Windows 8. Look, my favorite Commodore 64 emulator runs fine on Windows 8, so why would I ever go back?

That’s it. I started eating the Windows 8 dog food a long time ago and am enjoying every bite.

Thanks to David Gewirtz for the original article that inspired this post.

Monday, November 26, 2012

Koch Snowflakes on Windows 8 with XAML

A few years back I wrote a little program that would generate Koch snowflakes in Silverlight. After brisk walk in the cold weather today, I decided it was time to port it over to Windows 8, more just to see how easy it would be. It turns out it only took about 5 minutes to have the program up and running. I made a few tweaks, and it works. I spent some more time just changing how the snowflakes are updated. It is definitely far from perfect (there is an occasional unhandled exception I haven’t debugged and it pegs the CPU) but it’s still a fun little project to run and see.

The Koch curve is simple. You start with a line segment, break it into thirds, and extend the middle third into a triangle. You then repeat the process with the outer line segments recursively. This image depicts the process:

Working backwards, the implementation for the Windows Store app starts with a helper method that takes a set of points and turns them into a path so we can render the snowflake on the XAML surface:

private static Path CreatePath(IReadOnlyList<Point> points)
{
   
var segments = new PathSegmentCollection
();

   
foreach (var point in
points.Skip(1))
    {
        segments.Add(
           
new LineSegment
                {
                    Point = point
                });
    }

   
var pathGeometry = new PathGeometry
();

   
// pull the segments into the geometry
    pathGeometry.Figures.Add(
       
new PathFigure
            {
                IsClosed =
true
,
                StartPoint = points[0],
                Segments = segments
            });

   
return new Path { Data = pathGeometry };
}

The points turn into segments then are collapsed into a closed path. Next, two points need to be split into thirds with a triangle in the middle. The following method does that. It turns 2 points into 5, so the first and last are returned “as is” while the middle triangle is produced using some trigonometry and randomness:

private static IEnumerable<Point> RefactorPoints(Point a, Point b)
{
   
// first point
    yield return
a;

   
var
dX = b.X - a.X;
   
var
dY = b.Y - a.Y;

   
// 1/3 of the way from first point to second point
    yield return new
Point(a.X + (dX / 3.0), a.Y + (dY / 3.0));

   
var
factor = Random.NextDouble() - 0.5;

   
var vX = ((a.X + b.X) / (2.0 + factor)) + ((Math
.Sqrt(3.0 + factor) * (b.Y - a.Y)) / (6.0 + (factor * 2.0)));
   
var vY = ((a.Y + b.Y) / (2.0 + factor)) + ((Math
.Sqrt(3.0 + factor) * (a.X - b.X)) / (6.0 + (factor * 2.0)));

   
// apex of the middle triangle
    yield return new
Point(vX, vY);

   
// 1/3 of the way from the second point to the first point
    yield return new
Point(b.X - (dX / 3.0), b.Y - (dY / 3.0));

   
// second point
    yield return b;
}

Now we know how to break down a side. This is done recursively for several levels and the points are aggregated back:

private static IEnumerable<Point> RecurseSide(Point a, Point b, int level)
{
   
// iterations are done, so return this line segment
    if
(level == 0)
    {
       
return new List
<Point> { a, b };
    }

   
// first we need to build a list of points that make the refactoring of the side
    var
newPoints = RefactorPoints(a, b).ToList();

   
// this breaks down the segment into 5 points
    var aggregatePoints = new List
<Point>();

   
for (var
x = 0; x < newPoints.Count; x++)
    {
       
var
y = x + 1 == newPoints.Count ? 0 : x + 1;
        aggregatePoints.AddRange(RecurseSide(newPoints[x], newPoints[y], level - 1));
    }

   
return aggregatePoints;
}

Now the whole process is kicked off by a triangle – not a perfect triangle and the midpoint is randomized a bit, but enough to get the process started to generate a snowflake. As I noted in my post a few years back, you could probably eliminate the second and third calls for recursion and simply reflect a single side:

public static Path Create()
{
   
// something to start with
    var a = new
Point(0, 0);
   
var b = new
Point((Random.NextDouble() * 70.0) + 15.0, 0);
   
var c = new
Point(0, b.X);

   
// now we refactor as many times as needed
    var
levels = Random.Next(Min, Max);

   
// first set of points (first triangle)
    var points = new List
<Point>();
    points.AddRange(RecurseSide(a, b, levels));
    points.AddRange(RecurseSide(b, c, levels));
    points.AddRange(RecurseSide(c, a, levels));

   
// walk the sides and iterate them
    var retVal = CreatePath(points);
}

The original example had colorful snowflakes. This time I’m going for a more black and white effect, so I generate a random gradient based on some shades of gray with a random transparency value.

kochsnowflakes

I then wrap the snowflake entity in a class that knows how to insert itself into a canvas (a delegate is passed in so it doesn’t have to take a hard reference on the canvas):

public SnowFlakeEntity(Action<Path> insert, bool fromTop)
{
   
this.snowflake = SnowFlakeFactory
.Create();

   
this
.affinity = Random.NextDouble();

   
// set velocity, initial x and y
    this
.velocity = (Random.NextDouble() * 10.0) + 1.0;
   
this
.x = Random.NextDouble() * Left;
   
this
.y = fromTop ? -100.0 : Random.NextDouble() * Top;

   
// set it
    this.snowflake.SetValue(Canvas.LeftProperty, this
.x);
   
this.snowflake.SetValue(Canvas.TopProperty, this
.y);

   
// place onto surface
    insert(this
.snowflake);

   
// remember parent
    this.surface = this.snowflake.Parent as Canvas
;

   
this.NextTick = DateTime.Now.Add(Interval);
}

It is set up with an initial position and velocity, as well as an interval to update it. If I wasn’t randomizing the motion, I could get away with a storyboard (and potentially have much better performance and less CPU utilization) but the motions are randomized to appear more “organic” as you can see in the following method. The affinity affects the drift direction and the rate of spinning/twisting. The snowflake falls and drifts, and when it is “out of bounds” is removed from the canvas so a new flake can be born:

public void Frame()
{
   
// fall
    this.y = this.y + this
.velocity + (3.0 * Random.NextDouble()) - 1.0;

   
// is it offscreen?
    if (this
.y > Gone)
    {
       
this.surface.Children.Remove(this
.snowflake);

       
// notify the outside world that things changed
        var handler = this
.SnowflakeDied;
       
if (handler != null
)
        {
            handler(
this, EventArgs
.Empty);
        }
    }
   
else
    {
       
// nudge it
        var factor = 10.0 * this
.affinity;
               
       
if (this
.affinity < 0.45)
        {
            factor *= -1.0;
        }
               
       
this.x = this
.x + (Random.NextDouble() * factor);

       
// left edge
        if (this
.x < 0)
        {
           
this
.x = 0;
           
this.affinity = 1.0 - this
.affinity;
        }

       
// right edge
        if (this
.x > Left)
        {
           
this
.x = Left;
           
this.affinity = 1.0 - this
.affinity;
        }

       
this.snowflake.SetValue(Canvas.LeftProperty, this
.x);
       
this.snowflake.SetValue(Canvas.TopProperty, this
.y);
    }

   
// spin
    var rotate = (RotateTransform)this.snowflake.GetValue(UIElement
.RenderTransformProperty);
    rotate.Angle += Random.NextDouble() * 4.0 *
this
.affinity;

   
// rotate
    var plane = (PlaneProjection)this.snowflake.GetValue(UIElement
.ProjectionProperty);
   
var rotateFactor = 6.0 * this
.affinity;
    plane.RotationX += Random.NextDouble() * rotateFactor;
    plane.RotationY += Random.NextDouble() * rotateFactor;
    plane.RotationZ += Random.NextDouble() * rotateFactor;

   
this.NextTick = DateTime.Now.Add(Interval);
}

This is all managed by a behavior that attaches to the canvas. The behavior can update the size when the canvas changes, so the snowflakes fall within the confines of the surface regardless of the orientation or if the app is snapped (when you snap it, you just get a greater density of snowflakes). You can see the adjustment happening when you unsnap as snowflakes fall off the bottom and begin to appear in the additional space provided by the unsnapped view.

The older implementation used a set of dispatcher timers unique to each snowflake to update them. This felt a little unwieldy for a store app so I centralized it to a single task. If the application is suspended the task simply freezes and resumes when restarted, and if the app is terminated, so is the task and the entire thing can simply start over again when the user returns. I don’t like infinite loops so I could probably set a variable that is updated on suspension, but this gets the job done for now:

private static async void ThinkLoop(CoreDispatcher dispatcher)
{
   
while (true
)
    {
       
var
now = DateTime.Now;
       
var
snowFlake = Snowflakes.FirstOrDefault(s => s.NextTick <= now);
       
while (snowFlake != null
)
        {
           
var
flake = snowFlake;
           
await dispatcher.RunAsync(CoreDispatcherPriority
.Normal, flake.Frame);
            now = DateTime.Now;
            snowFlake = Snowflakes.FirstOrDefault(s => s.NextTick <= now);
        }
       
await Task
.Delay(1);
    }

}

Notice the task simply loops and finds the next flake that is eligible to update, then dispatches the update to the UI thread. The await is important to avoid clogging the thread (if I were to simply spam the dispatcher with tons of requests, the dispatcher would hit its quote and the app would get terminated). The delay is also fairly arbitrary but keeps the loop from spinning non-stop and instead adds a little bit of a break.

The behavior attaches to the canvas loaded event (and the resized to notify the snowflakes where they are allowed to drift) and kicks off the task, like this (notice the delegate being passed to attach the snowflake to the canvas):

private static void CanvasLoaded(object sender, RoutedEventArgs e)
{
   
var canvas = sender as Canvas
;

   
if (canvas == null
)
    {
       
return
;
    }

   
SnowFlakeEntity
.Left = canvas.ActualWidth;
   
SnowFlakeEntity
.Top = canvas.ActualHeight + 50.0;
   
SnowFlakeEntity
.Gone = canvas.ActualHeight;

   
for (var
index = 0; index < Snowflakes.Capacity; index++)
    {
       
var snowflake = new SnowFlakeEntity
(o => canvas.Children.Add(o));
        snowflake.SnowflakeDied += SnowflakeSnowflakeDied;
        Snowflakes.Add(snowflake);
    }

   
Task.Run(() => ThinkLoop(canvas.Dispatcher));
}

When a snowflake “dies” it is removed from the collection that the behavior is tracking as well as the canvas surface:

private static void SnowflakeSnowflakeDied(object sender, EventArgs e)
{
   
var snowflake = sender as SnowFlakeEntity
;

   
// get the surface so we can add the next snowflake to the same surface
    if (snowflake == null
)
    {
       
return
;
    }

   
var
canvas = snowflake.Surface;
    Snowflakes.Remove(snowflake);
   
var newFlake = new SnowFlakeEntity(o => canvas.Children.Add(o), true);
    newFlake.SnowflakeDied += SnowflakeSnowflakeDied;
    Snowflakes.Add(newFlake);
}

The XAML uses the behavior to kick everything off. A light gradient helps the flakes show up with more contrast. There is also an event that fires when the size of the canvas changes to update the bounds of the clip. The clip ensures snowflakes don’t appear outside of the row designated for snowflake activity.

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <TextBlock Text="Koch Snowflakes" Style="{StaticResource HeaderTextStyle}" Margin="12"></TextBlock>
    <Canvas Grid.Row="1"
 
          
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
           SizeChanged="FrameworkElement_OnSizeChanged"
           local:SnowFlakeBehavior.AttachSnowFlake="True">
 
       
<Canvas.Background>
            <LinearGradientBrush>
                <GradientStopCollection>
                    <GradientStop Color="Black" Offset="0"></GradientStop>
                    <GradientStop Color="#888888" Offset="1.0"></GradientStop>
                </GradientStopCollection>
            </LinearGradientBrush>
        </Canvas.Background>
        <Canvas.Clip>
            <RectangleGeometry x:Name="CanvasClipper" Rect="0,0,9999,9999"/>
        </Canvas.Clip>
    </Canvas
>
</
Grid
>

That’s it. You can download the full source here. Don’t have Visual Studio or don’t care to compile it? You can side load it with the app package here. I’m sure I could create a much better experience using Direct2D but this was literally an attempt to port an existing app. I was very pleasantly surprised to find so little had to be changed from my Silverlight implementation. Enjoy the snowflakes!

Monday, November 19, 2012

Building a JavaScript Event Aggregator using TypeScript

The event aggregator is a useful mechanism for decoupling notifications. Typically, notifications happen through events. In JavaScript, an event is a notification that happens as the result of an action. You can think of it as a notification that is triggered by something. We call the triggering of the event “raising” the event. Events are a simple notification mechanism that contain a collection of handlers. A handler is really just a function that is called when the event is raised. The event may pass some information to the handler, and your function must react to the event.

Perhaps the most popular event in JavaScript is the “click” event. Events can be wired directly in HTML markup, like this:

<a id="homeLink" href="#home" onclick="alert('Go Home!')">Go Home</a>

A more sophisticated way to provide a handler is to do something like this:

var homeLink = document.getElementById('homeLink');
homeLink.onclick = function(e) {
   alert('Go Home!');
}

Here, the handler is assigned to the onclick function that is raised when the link is clicked.

Events are the core of interacting with HTML DOM. Many JavaScript frameworks provide a mechanism for you to extend JavaScript objects to participate in the event model as well. For example, using Backbone’s events you can register to an event that is triggered by a business object, and raise the event from the business object. This allows you to have events that are not tied to specific user actions in the DOM.

The event model makes sense for most cases. One complaint about this model is that it does force coupling. To register for an event, you must have a reference to the object or DOM element that triggers the event. You provide your handler directly to the source of the event. This is appropriate in most cases, because coupling isn’t always a bad thing. A common example of this is entering search criteria for a grid and pressing the search button.

The search criteria is often bound to a view model that contains properties for the search criteria. The search event will fire, and this will trigger a call to a service that passes the criteria and returns the results for the grid. While these actions should be decoupled to an extent (i.e. the view model will remain free of view-specific code to keep it testable and maintainable, and the service call is probably implemented in a separate function), it makes sense for the view model to be aware of the service because there is a direct action/reaction taking place – the action is to request the list of results and the reaction is to receive the list. Decoupling these (for example, simply sending a message that states, “I want data” and then having a completely separate mechanism to listen for the message “I have data”) can make the code confusing to follow, hard to troubleshoot and difficult to maintain.

There are a few scenarios such as cross-module communication and extensibility that make more sense from a highly decoupled perspective. For cross-module communication, for example, you may want to use an event aggregator. One module may focus on the process of searching for items and adding them to a shopping cart, while another module handles tracking the shopping cart. You may eventually add a third module and extend the application by providing a shipping estimation calculator that responds with a new total whenever items are added to the cart. In these cases, you can decouple the modules by sending a generic message that an item is selected, then build the other modules to receive that message and act on it.

To facilitate this, you can use the publisher/subscriber model as implemented by the event aggregator. The concept of an event aggregator is simple: you have a “broker” that manages notifications. All modules know about the broker, but not about each other, and publish messages to the broker. The broker maintains a list of subscriptions (modules “subscribe” to messages) and notifies the subscribers when a message is listed.

This pattern is a perfect example of how TypeScript can be used to build a facility without compromising the flexibility of the JavaScript language. TypeScript is a superset of JavaScript, so all valid JavaScript is also valid TypeScript code. Instead of trying to replace the language or force typing, TypeScript allows you to define contracts and types where they make sense and are expected, but retain full control over the power of the dynamic and function-oriented aspects of JavaScript.

I decided to start by developing an MVVM module I’ll call Gom because it’s the glue that we can use on the client to hold things together. I’m exploring this solely as a learning exercise as there are plenty of fantastic frameworks like KnockoutJS, AngularJS, and the framework built into Kendo UI that handle data-binding and enterprise concerns. In TypeScript, a module is like a namespace and can be simply defined like this:

module Gom {
}

That’s it – now I can start defining classes and methods that are specific to my module. The first thing I want to keep track of is subscriptions. A subscription is simply a callback – it’s a function that should be called when a notification is sent (or an event is raised). In this model, I’ll give the subscription an identifier as well so the listener can unsubscribe if it is no longer interested in the notification:

class Subscription {
   
constructor
(           
       
public id: number
,
       
public callback: (payload?: any) => void) {
    }       
}

Note the signature for a function can be declared using a lambda-style expression, showing the parameters that are expected and the return type. The implementation of the class in JavaScript is a self-invoking function scoped to the Gom module:

var Subscription = (function () {
   
function
Subscription(id, callback) {
       
this
.id = id;
       
this
.callback = callback;
    }
   
return Subscription;
})();   

What’s nice is that I don’t have to worry about things like creating a constructor or wrapping the function – TypeScript does that for me. Next, I’ll create an interface for a message. Think of a message as a “channel.” I can send a type of message (giving it a name), and I’ll keep track of all subscriptions for that message. It is assumed that both publishers and subscribers understand how to deal with the content of messages that have the same name. In TypeScript, interfaces have no actual JavaScript implementation. They simply provide compile-time checks, design-time auto-completion and help keep your code clean and make it easier to build and maintain.

interface IMessage {
    subscribe(callback: (payload?:
any) => void): number
;
    unSubscribe(id:
number): void
;
    notify(payload?:
any): void;
}

The subscription takes a callback which has the signature of expecting any type of object (optional) and returning nothing (this is the function the listener will implement) and returns a number (the token for the subscription so it can be unsubscribed). The unsubscribe function takes the identifier, and the notify function takes an optional payload.

We can now implement the interface:

class Message implements IMessage {

   
private
_subscriptions: Subscription[];
   
private _nextId: number
;

   
constructor (public message: string
) {
       
this
._subscriptions = [];
       
this._nextId = 0
;
    }

   
public subscribe(callback: (payload?: any) => void
) {
       
var subscription = new Subscription(this
._nextId++, callback);
       
this
._subscriptions[subscription.id] = subscription;
       
return
subscription.id;
    }

   
public unSubscribe(id: number
) {
       
this
._subscriptions[id] = undefined;                       
    }

   
public notify(payload?: any
) {
       
var
index;
       
for (index = 0; index < this
._subscriptions.length; index++) {
           
if (this
._subscriptions[index]) {
               
this._subscriptions[index].callback(payload);
            }
        }
    }
}

Notice how the message maintains it’s own list of subscriptions. For efficiency, it keeps the subscriptions in their assigned slots and simply sets them to undefined when they are unsubscribed. A notification simply iterates through the array and sends the payload to the subscriptions. Empty slots are skipped.

The implementation in JavaScript is again as self-invoking function that scopes the variables appropriately. Note the public functions are class-wide and therefore assigned to the underlying prototype for the object:

var Message = (function () {
   
function
Message(message) {
       
this
.message = message;
       
this
._subscriptions = [];
       
this
._nextId = 0;
    }
    Message.prototype.subscribe =
function
(callback) {
       
var subscription = new Subscription(this
._nextId++, callback);
       
this
._subscriptions[subscription.id] = subscription;
       
return
subscription.id;
    };
    Message.prototype.unSubscribe =
function
(id) {
       
this
._subscriptions[id] = undefined;
    };
    Message.prototype.notify =
function
(payload) {
       
var
index;
       
for(index = 0; index < this
._subscriptions.length; index++) {
           
if(this
._subscriptions[index]) {
               
this
._subscriptions[index].callback(payload);
            }
        }
    };
   
return Message;
})();   

All of the classes so far have been scoped internally to the module. This means they are local to the self-invoked function that defines the module, but not available externally. You can’t directly create a Message instance. Instead, I expose an EventManager class. This is exported in TypeScript so it can be referenced externally from the module. The event manager handles a list of messages and exposes the various operations:

export class EventManager {

   
private _messages: any
;

   
constructor
() {
       
this
._messages = {};
    }

    subscribe(message:
string, callback: (payload?: any) => void
) {
       
var
msg: IMessage;           
        msg =
this
._messages[message] ||
            <IMessage>(
this._messages[message] = new
Message(message));
                      
       
return
msg.subscribe(callback);                       
    }
       
    unSubscribe(message:
string, token: number
) {           
       
if (this
._messages[message]) {
            (<IMessage>(
this
._messages[message])).unSubscribe(token);
        }
    }

    publish(message:
string, payload?: any
) {
       
if (this
._messages[message]) {
            (<IMessage>(
this._messages[message])).notify(payload);
        }
    }
}

Now you can see some more powerful TypeScript features at work. The subscriptions simply exist as properties on the main _messages object. When a subscription comes in, the existence of the Message instance for that subscription is checked, otherwise it is created. The <IMessage> casts the result so you can use auto-complete (type msg and hit the period and you’ll see the list of available methods). This example passes the subscription through to the message.

To unsubscribe the function first checks that the message exists, and only if it does, it passes the token down to unsubscribe. Finally, the publication checks for the existence of subscriptions (if no one subscribed, there is no one to notify) and then passes the payload through. The generated JavaScript (note the assignment to the Gom module so it is available for external consumption):

var EventManager = (function () {
   
function
EventManager() {
       
this
._messages = {
        };
    }
    EventManager.prototype.subscribe =
function
(message, callback) {
       
var
msg;
        msg =
this._messages[message] || (this._messages[message] = new
Message(message));
       
return
msg.subscribe(callback);
    };
    EventManager.prototype.unSubscribe =
function
(message, token) {
       
if(this
._messages[message]) {
            ((
this
._messages[message])).unSubscribe(token);
        }
    };
    EventManager.prototype.publish =
function
(message, payload) {
       
if(this
._messages[message]) {
            ((
this
._messages[message])).notify(payload);
        }
    };
   
return EventManager;
})();
Gom.EventManager = EventManager;  

Now I can demonstrate the pub/sub model through a simple page. Here is the full mark-up. The TypeScript is compiled to a corresponding JavaScript file that is referenced.

<!DOCTYPE html>
<
html xmlns
="http://www.w3.org/1999/xhtml">
<
head>
    <title>GOM - MVVM Glue for JavaScript</title>   
</head
>
<
body>
    <div><input id="txtMessage" value=""/></div>
    <div><input type="button" id="btnSubmit" value="Publish"/></div>
    <div>
        <h1 id="header">Pub/Sub Example</h1>
        <p id="paragraph">Type a message in the box and click "publish" to continue.</p>
    </div>
    <script src="Scripts/GomEvents.js"></script>
    <script type="text/javascript">
        var events = new
Gom.EventManager();
       
       
var token = events.subscribe("message", function
(msg) {
            document.getElementById(
"header"
).innerText = msg;
        });

        (
function
(tok) {
            events.subscribe(
"message", function
(msg) {
                document.getElementById(
"paragraph"
).innerText = msg;
                events.unSubscribe(
"message"
, tok);
            });
        })(token);       

        document.getElementById(
"btnSubmit").onclick = function
() {
            events.publish(
"message", document.getElementById("txtMessage"
).value);
        };

   
</script
>
</
body
>
</
html
>

This is a very simple example but it illustrates the working event aggregator. Two subscriptions are made, one that will listen for the message called “message” and update an H1 tag, another that listens to the same message and updates the P tag. The second listener will also try to unsubscribe the first listener. The result is that the first message will update the H1 and P tags, while subsequent messages only update the P tag. Finally, a click event is wired to obtain the contents of the text box and publish the message. This is of course a contrived example to illustrate the implementation.

While you would never use the event aggregator for such as simple case, let’s go back to the original scenario of a shopping cart. The payload can be any type of object. In the shopping cart example, you could serialize an item added to the cart into JSON, then publish a “cartAdded” message with that as the payload. The cart module could then receive and track that item, while the shipping estimation module receives the same payload and uses it to estimate the shipping costs.

I believe TypeScript made it easier to design and build the implementation by using a class structure, while still generating clean JavaScript code. The resulting code can be consumed by any other code and doesn’t require TypeScript. More importantly, however, developers in a large enterprise project will now be able to reference the module and consume the contents with full IntelliSense, making it a lot easier to explore APIs and understand what they expect. Here’s an example of auto-completion in the IDE – note that I get a list of available functions as well as their complete signature:

typescriptintellisense

You can download the source for this post here. I leave you with this working example:

Enjoy!