Silverlight 2.0: Project template for self-resizing applications

Update: I posted an updated version which doesn't use JavaScript. See here.

One of the first things I often do when I create a new Silverlight application is to make it self resizing. This is not very difficult, because thanks to the goodness of WPF (of which Silverlight is a subset), resizing a scene only involves one simple operation: a ScaleTransform. This transform applies to a panel (in this case the top Canvas) and to all its children. Using a ScaleTransform, all the distances (dimensions, but also coordinates) are multiplied by a factor, so you don't need to move anything when the panel is resized. Additionally, since XAML graphics are vector-based, they will resize very gracefully (of course, if your application uses pixel-based graphics such as BMPs, PNGs, movies, etc..., then you will see pixels if you make the application very big).

The operations to make a Silverlight application self-sesizing are not very complicated, but they are annoying when you need to do it many times. This calls for automatization, according to the principles of pragmatic programming. To make this easier, I made a Visual Studio 2008 project template.

Downloading and installing the template

Installing the template is very easy: Simply download this Zip file and copy it without unzipping it to the folder "[MyDocuments]\Visual Studio 2008\Templates\ProjectTemplates\Silverlight\".

Then, in Visual Studio 2008, select the menu "File / New / Project / Silverlight / SelfResizingSilverlightTemplate".

File / New / Project / Silverlight / SelfResisingTemplate

The template will automatically be renamed according to the project name you enter in the "New project" dialog. There is just one catch: Visual Studio doesn't search-and-replace in the JavaScript code. So after you create your new project, you must replace manually the string "SelfResizingSilverlightTemplate" with your project name. Simply use the "Replace" dialog (Ctrl-Shift-H) in Studio.

After you're done, run the application by pressing Ctrl-F5. The Canvas has a yellow background, and I placed on rectangle in each corner, so that the resizing effect can be observed.

Self-resizing Silverlight application
How does it work?

For a Silverlight application to self-resize, it must get information from JavaScript. To do this, the Canvas and one of its methods are marked with the ScriptableAttribute, to enable JavaScript -> Silverlight communication.

Additionally, the main Canvas must be registered so that a JavaScript proxy is automatically created. This is done by using the method RegisterScriptableObject in WebApplication.Current, in the method Page_Loaded.

The OnResize method (which will be hooked to the Silverlight control's "onResize" event) takes care of resizing: A scale factor is calculated, and the ScaleX and ScaleY properties of the main Canvas' ScaleTranform are set accordingly. Additionally, the main Canvas is positioned in the middle of the screen (but that part can safely be removed if needed).

[Scriptable] public partial class Page : Canvas { private double _initialHeight = -1; private double _initialWidth = -1; public void Page_Loaded(object o, EventArgs e) { // Required to initialize variables InitializeComponent(); _initialHeight = this.Height; _initialWidth = this.Width; WebApplication.Current.RegisterScriptableObject("MainRoot", this); } [Scriptable] public void OnResize(uint pixelWidth, uint pixelHeight) { double factor = pixelWidth / _initialWidth; if (_initialHeight * factor > pixelHeight) { factor = pixelHeight / _initialHeight; } (this.RenderTransform as ScaleTransform).ScaleX = factor; (this.RenderTransform as ScaleTransform).ScaleY = factor; double actualWidth = _initialWidth * factor; double newLeft = Math.Floor((pixelWidth - actualWidth) / 2); if (newLeft < 0) { newLeft = 0; } this.SetValue<double>(Canvas.LeftProperty, newLeft); } }

In the JavaScript code, a method "handleOnResize" is hooked to the "onResize" event of the Silverlight control. This is done in the "handleOnLoad" method. The "handleOnResize" method does nothing but calling the corresponding C# method. So we have:

SelfResizeTemplate.prototype = { handleOnResize : function(sender, eventArgs) { if (!this._control) { return; } // Call code-behind this._control.content.MainRoot.OnResize(this._control.content.actualWidth, this._control.content.actualHeight); }, handleOnLoad : function(control, userContext, rootElement) { this._control = control; control.content.onResize = SelfResizeTemplate.createDelegate(this, this.handleOnResize); // Call onResize explicitly (needed for Firefox) this.handleOnResize(null, null); } }

The rest of the code is just here to take care of a few basic tasks, such as allowing the application to be called from multiple HTML pages, setting the control's background to a parameterized color, making it windowLess.

I hope that this template will be useful to you as it is to me.

Print | posted on Sunday, December 23, 2007 7:06 AM

Feedback

# re: Silverlight 2.0: Project template for self-resizing applications

left by Arne Claassen at 12/24/2007 10:03 AM Gravatar
Why not just use BrowserHost.Resize for the notification and then BrowserHost.ActualWidth & BrowserHost.ActualHeight for the resizing calculation? That way you never have to leave C#. I've been using that technique and it seems to work just fine.

# re: Silverlight 2.0: Project template for self-resizing applications

left by Laurent at 12/26/2007 2:39 AM Gravatar
Hi Arne,

Good catch! I was not aware of this. I ported the code I used in Silverlight 1.0 to 1.1, and didn't know you can get this information in C#. I will definitely update my template to take advantage of this, considering that avoiding the C#-to-JavaScript-to-C# conversions is a better idea.

Thanks,
Laurent

# re: Silverlight 2.0: Project template for self-resizing applications

left by Jeremy Turinetti at 1/9/2008 9:11 AM Gravatar
I have downloaded and used the updated version of your template and it works great except for a single issue. When I attempt to create and display a shape (an Ellipse in my case) it doesn't display properly. It relates to the line "WebApplication.Current.RegisterScriptableObject("MainRoot", this);". When I comment this line out the shape displays properly as it should, yet this removes the resizable functionality of the app. I created the Ellipse in the Page_Loaded event in the Page.xaml.cs file. Any ideas as to why this is, and how I can have both a resizable app and the ability to programmatically create shapes in C#?

# re: Silverlight 2.0: Project template for self-resizing applications

left by Laurent at 1/9/2008 9:22 AM Gravatar
Hi Jeremy,

Interesting issue. If you don't mind, I would like you to send me a repro of this problem. I suspect a bug in the rendering engine, and in this case I'll pass the issue to the Silverlight team at Microsoft (with all due credentials to you, of course).

Thanks,
Laurent

# re: Silverlight 2.0: Project template for self-resizing applications

left by Jeremy Turinetti at 1/9/2008 9:47 AM Gravatar
I just sent you a more detailed description using the Contact link at the top.

Thanks!

# re: Silverlight 2.0: Project template for self-resizing applications

left by Laurent at 1/10/2008 5:06 AM Gravatar
I just published a newer version which takes care of the bug that Jeremy found. For the records: The call to "WebApplication.Current.RegisterScriptableObject("MainRoot", this);" will fail with an exception, which doesn't crash the application, but prevents any code located after that call to be executed. This is why the Ellipse didn't show.

The reason why RegisterScriptableObject fails is that there is no Scriptable member defined in the template. If you have a Scriptable member, then you must add the call to RegisterScriptableObject again!

Greetings,
Laurent

# re: Silverlight 2.0: Project template for self-resizing applications

left by deef at 1/25/2008 4:21 AM Gravatar
Anyone know where I can find a sample of this in 1.0?

# re: Silverlight 2.0: Project template for self-resizing applications

left by Laurent at 1/25/2008 4:34 AM Gravatar
Hi Deef,

I'll try to find time this weekend to make one and post it here. Keep posted.

Greetings,
Laurent

# re: Silverlight 2.0: Project template for self-resizing applications

left by Abhijeet at 4/2/2008 1:15 PM Gravatar
I was trying installing template for silverlight 2.0 I could see new template under silverlight but when i add project it throws an error ....
The imported project"c:ProgramFiles\MSBuild\Microsoft\VisualStudio\v9.0\Silverlight\Microsoft.Silverlight.CSharp.targets"
was not found.Confirm that path in <Import> declaration is correct and that file exists on disk.......
Thanxs in advance.......

# re: Silverlight 2.0: Project template for self-resizing applications

left by Laurent at 4/3/2008 2:50 PM Gravatar
Hi Abhijeet,

This template is for SL 2 Alpha. I don't have a version for Beta 1 yet.

Greetings,
Laurent
Title  
Name
Email (never displayed)
Url
Comments   
Please add 6 and 8 and type the answer here: