Silverlight Limitations

November 20th, 2007

After a couple weeks of learning Silverlight, I’ve come across a number of annoyances which I know will come up again and again.

Centering text

There’s no Alignment attribute for TextBlocks. To center text you need to use an on-load event to reposition the text after it’s created.

No inline custom controls

Let’s say you know you’ll use centered text a lot. So you create a custom control with a TextBlock that centers itself. You want to be able to easily insert is into your XAML.

But you can’t. As I understand it, the purpose of XML is to allow things like this. Even though Silverlight has its own schema to define the tags that can be used, it would be nice to be able to add your own. Even something like a CustomControl tag would be enough. But with Silverlight you have to go back to an on-load event.

Copying brushes

This is one I just experienced a few minutes ago, and I’m not sure how significant it will be. Say you’re making something like a drawing program, and you want to be able to select a color, or brush, and paint with it. I’d like to be able to do something like this:

You can’t, because you would have two objects using the same brush. Even something like r.Fill = currentBrush.Clone() would be nice. This is what I ended up with:

Eww.

But, Silverlight 1.1 is still in alpha, so it’s still being tweaked. There’s a chance some of this will be much easier in the final version.

Resizing a Silverlight canvas

November 10th, 2007

Let’s say you want your Silverlight canvas to resize to fill the browser window, or at least to fill its container.

I expected to find a simple way of defining what happens when the canvas container is resized. Something similar to the Loaded attribute. But it’s a little more complicated than that. We need to handle the event in JavaScript and call our managed code to do the actual resizing from there.

First we set up the managed code to make it callable from JavaScript. To do this you need include to add the [Scriptable] tag to your class and all methods that will be called from JavaScript ([Scriptable] is in System.Windows.Browser). Then, in the page loaded method, register the scriptable methods using WebApplication.Current.RegisterScriptableObject.

Now we can call Resize from JavaScript. All we have to do is set up the event handler. But you can’t declare the event handler in the events section of Silverlight.createObjectEx. I decided to use an old-fashioned JavaScript event handler:

This works when the window is resized, but it won’t work if the canvas container is resized for some other reason. I’ll get to a better solution in a minute, but first let’s look at how it works, because we’re going to keep the contents of the function.

SilverlightControl is the id of the Silverlight object, as defined in the createObjectEx call. Content.basic.Resize is created in the C# code above. “basic” could be anything, but I stuck with what I saw in the tutorial I read.

This almost gets the job done, but it’s better to use the Silverlight resize event. The only way I could find to do this is to set it up in JavaScript after the Silverlight object is created.

onLoad is the function called when the object is created, as specified in the createObjectEx call. And Content.onResize is the resize handler, which unfortunately isn’t in Intellisense, but is in the MSDN article on Silverlight resizing, which appears to be very incomplete and incorrect.

Now just create another JavaScript function with the same code as the resize handler above, and we’re good to go. All that’s left is to actually resize the canvas and the objects. If you just want everything to scale with the canvas, you can use a ScaleTransform and set ScaleX and ScaleY in the C#. The XAML:

And the C#:

In this case, the canvas starts at 640×480, so our scale factors are based on those numbers.

Resizable Silverlight example

That’s all there is to it. Here is the project I made, which includes a slightly more complex Resize method.

Learning Silverlight - part 2

November 5th, 2007

A few days ago I wrote about getting started with Silverlight 1.0. But Silverlight 1.1 is coming in the near future, and for developers, the future is now. The biggest change with 1.1 is that it includes the .NET framework, so applications can use languages like C#, not just JavaScript.

To use 1.1, you need Visual Studio 2008 Beta 2 Standard or Pro (NOT Express), the , and the Silverlight 1.1 SDK.

The best place to get started is at Microsoft’s Silverlight page, in the Getting Started section (imagine that). They start out with a simple clock for the first example.

Silverlight clock

The project is similar to a version 1.0 project. There’s the XAML with the canvas objects and storyboards, and the HTML and the common JavaScript to create the object. But now there’s also a C# class to take the place of the JavaScript. I like learning by doing, and here I decided to learn by adding a millisecond hand.

Each hand is a XAML Paths which is rotated with a simple repeating animation. I copy the SecondHand object to create a msHand and edit its shape. The example uses inline path markup syntax, something I hadn’t come across yet.

The Data attribute here defines a path that starts (M) at (-1.5, 16) (in the Silverlight canvas, (0, 0) is in the top-left), and moves (l) down by (0, 70), then left (3, 0), then up (0, -70), and finally closes (z). That’s the second hand. I want the millisecond hand to be thinner, longer, and darker.

Each path also contains a Path.RenderTransform element which defines its angle, and is needed for the path to rotate. Now to animate it.

This is the second-hand animation, which just changes the object’s angle from 180 to 540 over 1 minute and repeats forever. Adapting it to the millisecond hand is simple:

The only differences are the target and the duration. The final step is the set up the initial condition. The path definitions create all hands pointing down, towards 6, but we want them to represent the current time. This is where the C# codebehind comes in. But first, how do we get to the code-behind? Well, in version 1.0 the Canvas (root) of the XAML file had a Loaded attribute which pointed to the JavaScript function to call upon loading. In 1.1 it’s the same, but there are also a few attributes to define the namespace:

x:Class tells Silverlight that we’re using the ClockCanvas class in SilverlightProject8.dll. The Canvas_Loaded method contains C# code to find the canvas (Canvas can = sender as Canvas), find the animations (DoubleAnimation secAnim = (DoubleAnimation)can.FindName("secondAnimation")), calculate the current time, and move the hands into position:

The To and From properties of the animation object correspond to the respective attributes in the XAML. Adding 180 is done so the “default” is up instead of down (if date.Second is 0, the angle would be 0 and the hand would point down because of the Path definition, but we want it to point up). Duplicate this code for the new millisecond hand and replace .Second with .Millisecond, and we’re done. We now have a 4-hand clock.

Silverlight clock with millisecond hand

Learning Silverlight - part 1

November 2nd, 2007

So I decided to learn Silverlight. I figure it’d be nice to have experience with one of those RIA frameworks - Silverlight, JavaFx, AIR - and Silverlight seems the least evil to me.

My favorite way to learn a new language or framework or technology is to download a few simple examples and try to change them. Tutorials and books are nice, but real, working code has no equal. I started with a photo gallery from Design With Silverlight (which has plenty of other good examples). Load; compile; run. It does what I expect, and I see a few things I can change. But I won’t get into the boring details of what I did with the code, I’m just going to give an overview of how Silverlight works. All the snippits here are modified (simplified) versions of code from the photo gallery example.

A Silverlight app, at least version 1.0, consists of 3 parts: the HTML, the XAML, and the JavaScript. The HTML can be as simple as a div and a call to JavaScript function createSilverlight().

The XAML contains the descriptions of objects and animation in the canvas. Here are a couple examples:

This creates a 600×30 rectangle with a gradient so it’s black on the left, white on the right, and red in the middle. The MouseEnter and MouseLeave attributes define the JavaScript functions that will be called on their respective events. The Canvas.RenderTransform node sets the scale properties of the object. It’s needed in case we want to rescale the object.

This creates a storyboard (basically an animation) that will scale an object 1.5x over 1 second. DoubleAnimationUsingKeyFrames defines what property will be animated, and SplitDoubleKeyFrames defines the times and values.

The JavaScript contains the meat of the application (at least in this example). The most important piece is Silverlight.js, which is distributed by Microsoft and initializes the Silverlight objects. This will be the same in every app, and as far as we’re concerned for now it could be black magic.

Then there’s the app-specific code that does things like handle events.

This is the previously mentioned function called from the HTML page which will create the Silverlight object with the specified properties. Every app will have something like this.

This is the callback for the mouseEnter event, as specified in the first XAML snippit. It looks for the mouseEnter canvas object, defined in the second snippit, and calls begin to start the storyboard. Line 3 sets the target of the storyboard so it points to the same object that fired the event. So if you mouse-over the rectangle, it will call this function, which will run the storyboard and scale the rectangle.

That’s really all there is to getting started. Canvas objects are in the XAML with references to event callbacks. Animations are also in the XAML. And event handlers which can start animations and change object properties are in the JavaScript.