Random geekery since 2005.

Husband, father, programmer, speaker, writer, blogger, podcaster, collector, traveler, golfer.

I’ve been talking technology for a while here, but it’s about time I start adding some value. I already mentioned the JUXtapose blog, so get over there for podcasts on User Experience and the technologies I use to make my UX and UI better.

Today, I want to talk about Silverlight 2 (Beta 1). One of the things that always frustrated me when creating a new application is that nobody ever wrote a good example of how to get my Silverlight application to scale with the random sizes of my user’s browsers. As long as I stay vector based, this application should look the same at 640×480 and 1280×1024. And if it makes sense to have it on a mobile phone, then let’s use the same application there too.

Today, my friends, I’ve got the simple steps you need to make your Silverlight 2 application scale effectively. I’ll start this tutorial after you’ve created your default application (there’s a great walkthrough on that here by Jesse Liberty).

I am using Visual Studio 2008, and Microsoft Silverlight Tools Beta 1 for Visual Studio 2008. My .entire solution can be downloaded here, so you can compare the changes I have made to a default project.

Step 1


If you followed the usual steps, your project should look something like mine.
Solution Explorer for this project.
We’re only going to be working in two files for this: Page.xaml, and its code-behind file, Page.xaml.cs. First, let’s take a look at the Page.xaml file, because more of our work will be code, not markup. Below is a shot of the entire XAML file (click to enlarge).
page.xaml contents
The only additions I have made to this file are the entire <canvas.rendertransform> section. I’ve also made the rootCanvas red, so that we can see it. One other thing that I have to credit Matt Casto for finding…you MUST define an initial size for your RootCanvas. Mine is 800×600, but you can use any size you’d like.

Step 2


Now we’ve got a little code to write, but it’s honestly pretty straightforward. We’ve got four things to add:

  1. an event handler for when the browser is resized.
  2. a Page_Loaded method to intialize everything.
  3. a proxy method for resizing our Silverlight control initially.
  4. a Resize() method for doing the heavy lifting.

Here’s a screenshot of my entire application namespace within the page.xaml.cs file (click to enlarge).
page.xaml.cs contents

First, we need to create a couple of variables. primarily, I need variables for the original height and width of my control before I get started. You’ll see why in a moment, but it’s basically to retain the “aspect ratio” of our control.

Second, in my “main” method, Page(), I route a new RoutedEventHandler to my Page_Loaded method when the XAML loads.

this.Loaded += new RoutedEventHandler(Page_Loaded);

Third, I have to create my Page_Loaded method. Here, I need to capture the original height and width, and I also add a new event handler to my application when the “host.content” = browser is resized. Finally, I call my Resize() method.

void Page_Loaded(object sender, RoutedEventArgs e)
{
_originalWidth = RootCanvas.Width;
_originalHeight = RootCanvas.Height;
Application.Current.Host.Content.Resized += new EventHandler(Content_Resized);
Resize();
}

Fourth, now that I have a new event handler pointing to Content_Resized(), I should probably write that method too. It just passes the call along to my Resize() method.

void Content_Resized(object sender, EventArgs e)
{
Resize();
}

Fifth and finally, I need to write my Resize() method. This is slightly more complicated than you might expect, but there’s a reason. We need to capture the width and height of the new browser size. That’s what currentWidth and currentHeight are for. uniformScaleAmount is what makes this complicated. We want to scale this thing uniformly, that is to say, if the application was originally 800×600, we want to keep a 4:3 ratio at all times, rather than stretching the app to fill the space allowed. Once we have determined the appropriate scale constant, we then also want to keep this app centered both vertically and horizontally in the browser as well. The last 4 lines of the code handle this, by altering the size of the overall control.

double currentWidth = Application.Current.Host.Content.ActualWidth;
double currentHeight = Application.Current.Host.Content.ActualHeight;

double uniformScaleAmount = Math.Min((currentWidth / _originalWidth), (currentHeight / _originalHeight));
RootCanvasScaleTransform.ScaleX = uniformScaleAmount;
RootCanvasScaleTransform.ScaleY = uniformScaleAmount;

double scaledWidth = Math.Min(_originalWidth * uniformScaleAmount, currentWidth);
double scaledHeight = Math.Min(_originalHeight * uniformScaleAmount, currentHeight);
RootCanvasTranslateTransform.X = (Math.Min(RootCanvas.ActualWidth, currentWidth) – scaledWidth) / 2d;
RootCanvasTranslateTransform.Y = (Math.Min(RootCanvas.ActualHeight, currentHeight) – scaledHeight) / 2d;
}

Please give this a try on your next application. You should be able to use this on any size Silverlight application, and as long as your creative assets can handle scaling to any size (read: vector), your application should look great at all sizes. Please leave me a comment if you give this a try…I want to know that I helped someone out!

Tags

6 responses to “How About Some Code? Simple Scaled Resizing In Silverlight 2 Beta 1”

  1. Annathar Avatar
    Annathar

    hi, where did u declare "parentCanvas"?

  2. Laurent Bugnion Avatar
    Laurent Bugnion

    Hi,I got pretty much the same code saved as a project template for SL 2 alpha (see http://tinyurl.com/3gfm26)Now I really have to do the same for Beta 1… If the days could only be a little longer :)Greetings,Laurent

  3. Ching Avatar
    Ching

    What if I wanted my canvas to resize its control’s positions proportionally? I want to keep the size of my controls on the containing canvas a fixed size, but I dont want them to float off the screen when the browser resized nor do I want them to be resized along with the canvas.

  4. Jose Walker Avatar
    Jose Walker

    Thanks buddy, It worked pretty fine, but I’ve to made some changes to make it work 100% correct.Here your code modified:double currentWidth = Application.Current.Host.Content.ActualWidth; double currentHeight = Application.Current.Host.Content.ActualHeight; double uniformScaleAmount = Math.Max((currentWidth / _originalWidth), (currentHeight / _originalHeight)); RootCanvasScaleTransform.ScaleX = uniformScaleAmount; RootCanvasScaleTransform.ScaleY = uniformScaleAmount; double scaledWidth = Math.Min(_originalWidth * uniformScaleAmount, currentWidth); double scaledHeight = Math.Min(_originalHeight * uniformScaleAmount, currentHeight); RootCanvasTranslateTransform.X = (Math.Min(parentCanvas.ActualWidth, currentWidth) – scaledWidth) / 2d; RootCanvasTranslateTransform.Y = (Math.Min(parentCanvas.ActualHeight, currentHeight) – scaledHeight) / 2d;

  5. John Stockton Avatar
    John Stockton

    Thanks, You probably saved me a couple hours of digging. I will definitly be stealing.. Um… I mean “Using”, this very soon, stay tuned for where and how 🙂

  6. advance cash payday Avatar

    Talent develops in tranquillity, character in the full current of human life.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at WordPress.com

%d bloggers like this: