Silverlight 1.0 full Javascript Intellisense
Everything we do here today is recorded in a 40 minute Webcast available at:
mms://ttvv.tv/users/publicftp/justinangel/intellisense.wmv
Let's create a new Silverlight 1.0 project in Expression Blend 2 August preview, change the background color of our first page to "LightGreen" and draw a small rectangle. This is how our XAML file looks like right now:
This basic XAML file has a Canvas and a rectangle on it. Let's change the rectangle so it will look like this:
And a Starboard so the rectangle changes background colors over a period of two seconds.
Finally we want a Javascript function called "CanvasLoaded" to fire when the canvas is loaded.
Let's see how this screen looks like in Expression Blend 2 August Preview:
Pretty straight forward. Now let's see our "CanvasLoaded" function that's located in our "Default_html.js" file using Visual Studio 2008 Beta2.
Well, this is the canvas loaded event so the sender must be of type Canvas!
We are sure to get intellisense for Canvas.
Wait, What??? No intellisense for Canvas?
Well, I'd like to print out the background color of our Canvas.
So what will we write?
hmm.. well, I guess I can work without intellisense and write something up.
Ok, We need Silverlight Javascript Intellisense!
How to setup Silverlight 1.0 Javascript Intellisense in Visual Studio 2008 Beta 2 with Visual Studio Extensions for Silverlight:
1. Go to http://www.Codeplex.com/intellisense and download the latest "Javascript Silverlight Intellisense" release.
2. Open the zip file. And we get two files:
3. Drag & Drop these two files into Visual Studio 2008 Beta 2 project.
4. Add a script reference at the top of our JS file.
5. Add a script src to intellisense.js in our HTML page.
That's It!
We're done.
You now have Javascript Intellisense for Silverlight 1.0.
First thing we have to do is convert our "sender" to a strongly-typed Canvas object.
Now let's see what we got from this strange Convert.ToCanvas function.
We get Full intellisense for Silverlight objects in our Javascript code!
We get properties, we get Events, We get methods, we get collections, we get indexers, and it's all strongly typed!
Working with Properties
So let's print out the background of our Canvas.
We even get SDK comments inside our Javascript!
But what's this... This background property gives us a "Brush"? What's a brush?
Wait, We used a SolidColorBrush, so what's the relation between that and This Brush thing?
Ok, So let's Convert our Brush to SolidColorBrush.
And we got the new Color property!
Let's print it out.
On our screen we get:
We got -7278960 which is an aRGB value that stand for LightGreen.
So let's do something a little more tricky, let's change the background for out Canvas.
We'll create a new SolidColorBrush.
And our background color has changed!
Working with Methods
Do you remember we added an animation so our Storyboard will change it's background colors?
Let's start that Storyboard.
Let's use the findName method on our canvas.
Did you notice our FindName method returns a "DependencyObject" type class?
We need to convert our general DependencyObject back to a Storyboard.
Before
After
Working with Events & Global Typed variables
Let's catch a left mouse button click and cause our canvas to change it's Opacity to 0.3.
We can see that our Canvas element is out of scope in the new OnMouseLeftButtonDown method, so we'll have to move someElement to a higher scope.
Let's see how are we dealing intellisense wise.
We get intellisense for someElement in CanvasLoaded after we converted sender to Canvas, but not inside OnMouseLeftButtonDown.
We need to define someElement as a global variable of type Canvas.
Not let's change the opacity to 0.3 like we wanted.
And the end result...
Before clicking left mouse button:
After:
Working with Inline Functions (Anonymous Delegates) & Attached Properties
Let's make our rectangle move around the Canvas as we press the arrow keys on the keyboard.

This is very similar syntax to that used by C# 2.0 Anonymous delegates.
In order to get which key was pressed we need our eventArgs.Key property, so let's convert our eventArgs.
I happen to know (because Jon Galloway told us) that "15" stand for the Up Arrow keyboard button.
Well, now we need to move our Rectangle up... So let's change it's "Canvas.Top" attached property.
Please note we are using "setValue" and "getValue" of DependencyObject and they aren't exclusive for Rectangle.
Let's create our "Canvas.Top" dependency property.
Before we click the up arrow button:
After:
Polymorphism and the Is/As patten
If you've ever used C# you'll be very familiar with the Is/As patterns for type conversion.
The Is Type Conversion pattern:
The As Type Conversion Pattern:
What we're seeing here is basic Polymorphism. We're getting a type of Perctangle, Changing it's reference type back to it's parent class DependencyObject and then back To Rectangle.
We have similar patterns to the C# Is/As patterns in our Javascript code.
The Javascript Is pattern:
The Javascript As pattern:
The "Convert.IsXXX" method returns a value whatever the element is convertible to XXX.
The "Convert.ToXXX" method returns null if the value is not convertible to XXX.
Working with Extension Methods
Let's say it's very common for us to change the "Canvas.Top" attached property we've seen earlier on Rectangles.
So common in fact, it should be an Extension Method.
We'd like to add it to the intellisense for Rectangle Class without changing the original class code.
The C# 3.0 Syntax looks like this:
We added a new method to our Rectangle class without even changing it's code!
Let's do the same in Javascript Silverlight objects.
We'll create a new file called "Extensions.js" (just because it's a good name):
We need to add a reference to our intellisense.js file.
I'll do that by selected the "intellisense.js" file in the Solution explorer and drag&drop into our Extensions.js file.
Let's add our Extension method to Rectangle.
We need to make sure "ChangeByHowMuch" is a known Number type so we'll add a param statement.
Now let's change the Canvas.Top of our Rectangle.
Now let's script tag reference to this Extensions.js file to our HTML page.
And we need to reference our Extensions.js file where ever need intellisense.
Please note that we not longer reference the intellisense.js file directly as our extensions.js reference it so we don't need to.
After running this code we can see the rectangle is on the bottom of our Canvas:
Type Safety, Element hidden field & Javascript Debugging
Let's take a look at this method:
It's expecting a Number of type Double. So this argument will be acceptable:
But what about...
Let's first run this code directly to the "Canvas" Silverlight clr type.
We can access it by using the "Element" hidden field on our Silverlight Javascript classes.
Notice that we don't get any intellisense for our element types.
We get this somewhat cryptic error message straight for the Silverlight 1.0 CLR:
Let's try this with our Silverlight Javascript Intellisense objects.
And we get:
Let's open our Call-stack window for debugging javascript.
And in the call stack we can see:
We can see it's a TypeSafety check that failed.
Let's double click on the second line:
And we can see in our editor:
Now, just for the heck of it, Let's open our Quick Watch Windows (CRTL + ALT + Q since VS2003) and evaluate "this".
We can see all the Properties, Methods and Events on our Silverlight Javascript Intellisense objects.
Let's examine "this.element" which is the normal Silverlight CLR 1.0 object.
Nothing, we get not Javascript debugging watch for native Silverlight objects.
Now, let's try to add a string to our "Canvas.Children" collection.
And we get the following runtime error:
Let's try something more subtle. Remember this code?
We used polymorphism to send a SolidColorBrush which inherits from Brush as a Brush Parameter.
Let's convert the SolidColorBrush back a DependencyObject and send it to the method:
This works fine and no errors are raised.
Let's try sending a Rectangle which is referenced as a DependencyObject.
We get the following error:
We need a Brush.
We can get a SolidColorBrush since it inherits from Brush.
We can get a DependencyObject of SolidColorBrush since SolidColorBrush still inherits from Brush.
We cannot Convert a DependencyObject of Rectangle to a Brush.
Deployment
Using the custom intellisense javascript syntax for development causes a deployment issue.
Do we deploy "intellisense.js" to our Client's browser? or do we Strip intellisense features from our Javascript code?
We can do which ever suits us.
Deployment with Intellisense.js file
Have a look at the file size of "intellisense.js":
It's more then 1mb! That's huge!
And most of it is essiently comments, spaces and variable names anyhow.
So with the download of the "intellisense.js" file you get a called "intellisense.compressed.js" which is a stripped down version of the "intellisense.js" file.
You can change the script tag HTML reference to this compressed JS file and your clients will only download the compressed version while you still get full intellisense.
As part of the generation of the "Intellisense.js" file we use Atif Aziz's Javascript compressor to create this compressed version.
You can see it only compresses to about 40% of the full intellisense.js file.
There are literally hundreds of javascript compressors out there and some compressed our "intellisense.js" file to a mere 100kb file.
If you want to find them just Google the phrase: "Javascript compressor" OR "Javascript shrink"
However, with the download I can only ship a compressed file from a .Net based software.
But feel free to use your own compressor on this file and deploy it as you please.
If you find a compressor with better results and It's written in .Net I'll be glad to use it.
Deployment without intellisense.js file
There two downloads the project's codeplex page at www.codeplex.com/intellisense.
The first contains only the two javascript files mentioned previously.
The second contains the code for the .Net software which generates the "intellisense.js".
Don't worry you don't need it.
Inside that software there's the following screen:
(What you're probably thinking right now is: "so, this is the guy that's telling me how to use Silverlight? that has to be the ugliest screen ever!")
Let's take the following javascript code we've written today:
And copy it into the "Javascript with intellisense" TextBox.
We get the same javascript code but without any of the intellisense features.
It uses the plain Silverlight CLR objects.
Here's the full translated code:
So we don't even need to include any JS file in our deployment scenario.
This little tool is only a small example of removing intellisense code from javascript.
We can use the same mechanism for a Visual Studio 2008 Add-in the translates code back & forth between intellisense code and non-intellisensed code.
We can create a small .Net IHttpHandler which will automatically serve to a browser request only javascript files after they have been stripped of intellisense code.
So regarding deployment, it's up to you.
If you need any help from me, you've got it.
Questions, follow-up and suggestions
Bugs
You will find bugs with this intellisense.
Seriously, I'm not that smart I can build a Type-system in 10 hours and it will work perfectly.
Please go to the project's codeplex page at http://www.codeplex.com/intellisense and Create a new Issue.
Write what error you received, add the appropriate Minimal & Relevant code.
If something isn't working as you expect it to, tell me what you expect and what actually happens.
Attach a print screen if possible.
Feature requests
Additionally, you might want additional features like the HttpHandler I talked about or more things to be strongly typed (DependencyProperties or Keys come to mind).
Same goes, open a new issue and I'll do my best.
Check for updates
This project will surely undergo constant changes in the first 30-60 days after publishing.
If you're using this project, please signup to our RSS feed so you get notices.
RSS feed can be found at: http://www.codeplex.com/intellisense/Project/ProjectRss.aspx
Here are my personal details just in case you feel the codeplex page isn't sufficient:
Email: J@JustinAngel.Net
Phone: +972 546 567789
I'm serious about this, don't hesitate to contact me.
Well, that's about it.
Justin-Josef Angel,
Senior .Net consultant, Microsoft C# MVP