Ok, I'll admit it, I'm a huge fan of Silverlight, it's been a while since a new piece of technology has sparked off so many ideas and new ways of thinking and most importantly, made it easy for a developer to get their head round. The main reason for this is arguably moving a compact version of the .NET CLR into the Silverlight plugin and its inclusion opens up a number of creative possibilities. Silverlight also delivers a number of capabilities for building a "real" application (or even an online experience which is similar/comparable with a desktop application built in WPF or Winforms) with controls such as datagrids, listboxes etc. Anyway, what I want to talk about today is probably going to turn into a huge post so I apologise in advance for the mass of content, I'll try and keep it readable *grin*
The "rat's nest" problem
When building an application of any discernible size or complexity, one of the main limiting factors to the robustness or flexibility of that application is co-ordinating, connecting and marshalling events between components. Generally we approach this task by exposing some public method on a class, wiring this method up to an event handler on a button or similar and from there we continue from there. Given that the majority of applications that you'd build with Silverlight are by the nature of the platform very event driven, you generally end up with a large number of methods and a lot of hardwired dependencies on those methods and events between the dependent parts of your application. This in itself is fine if you have a static application where the behaviour is fixed and you don't require runtime flexibility, but if you require more flexibility something more is needed.
Loosely coupled applications
The Silverlight team have clearly been thinking about loosely coupled applications because they included the capability to download pieces of a Silverlight application asynchronously and load them dynamically into the application domain. You can easily wrap this functionality behind a facade if you'd like and automatically retrieve additional application behaviour or presentation based on some runtime logic, or other events piped into your application. But that raises the question, if you wanted to call methods on these new pieces of functionality, how would you do it?
You could use reflection to inspect the class, extract the method you needed and invoke them from your event handler using reflection. Or taking this approach further, you could use reflection to harvest the methods that were available within a class and use some other rules to determine which ones to call and store these away for later use to make the event firing more generic. The general architectural approach to this is well established, in fact if you've ever played with the Microsoft Composite Application Block, or even the ASP.NET AJAX framework, or the Yahoo UI library, you'll have run into the observer pattern. I won't labour the point of explaining the observer pattern here, the Wikipedia article I linked to is more than sufficient to explain it, but basically it makes your life a lot easier when you're dealing with loosely coupled applications.
So, where now?
With all those previous points in mind, it became pretty obvious that having a loosely coupled, flexible eventing system in Silverlight would greatly reduce the complexity of building and deploying an application, whether it be in one great big chunk, or in separate assemblies. It would maintain the rich communication features made available using traditional hardwiring techniques, but additionally give you the flexibility to change those relationships at will. Fortunately because we have access to the .NET CLR and System.Reflection in particular, we can build something that will get us close to that goal. There are a couple of pre-requisite requirements for this to be as clean as possible and we will be relying on some of the .NET 3.5 Framework features specifically to make this happen, as well as the well-known functionality in System.Reflection.
.NET 3.5 Extension Methods
Simply put, extension methods allow you to extend the functionality of existing types without deriving from them, or recompiling or doing any of the other things that we'd traditionally have done to extend a type before. There's a great MSDN C# programming guide available here that goes into significantly more detail than this, so if you've not played with extension methods before - please read this first.
To keep with our goal of having as natural programming model as possible, we implemented a number of methods in the System.Windows.Controls namespace that extended System.Windows.Controls.Control and gave us access to some key features in anything that derives from control. Taking this approach means we can cover types that have visual presentation such as System.Windows.Controls.UserControl, or other types that just derive from System.Windows.Controls.Control. The real key methods in this group are as follows:
public static void Dispatch( ... )
{
EventManager.Current.Dispatch( id, e, callBack, behavior );
}
public static void Register( ... )
{
EventManager.Current.Subscribe( sender );
}
** Note: We will get to EventManager in the next post
There's a few overloads of these methods to support a couple of different implementation patterns, but notionally they do the same thing - register the control, and dispatch methods. In the same EventBase.cs you will also see the definition of a custom attribute [EventListener(...)], this is the magic glue that we use when reflecting against a class to discover methods that are marked as executable using the eventing infrastructure. It's not necessarily true that every method defined in a class will be required to be available so using the attribute decoration selectively allows you to choose which methods you want to expose, and which you do not.
In the next post I'll continue drilling in to the
underlying infrastracture, so till next time.