Tuesday, July 03, 2007

Silverlight: Resizing a Canvas and its Child Elements - Together

I was reading through the Silverlight forums this evening when I came across a seemingly obvious question, that had an answer that surpised me. Well, it probably wouldn't have surprised anyone else, but hey...

The question asked was basically 'When I resize a Canvas object, how do I resize all of the child elements of the Canvas as well?'.

My first thought was to iterate over the children collection of the Canvas, increasing each child elements Width and Height properties. And so I set off to try it out. Sure enough it worked, but the child elements started overlapping each other as they increased in size, which wasn't part of the plan. So I simply reset the Canvas.Top and Canvas.Left properties as well, and that worked, problem solved. Well, there is a much simpler way. Another developer posted the answer, which should have been obvious: Simply use a ScaleTransform to scale the Canvas, and all children will scale as well. Ahhh yes, much easier!

The following code shows both methods, and I know which one I will use next time I need to resize a canvas and its child elements:

The XAML:
<Canvas  
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640"
Height="480"
>
<
Canvas
x:Name="CanvasToResize"
Width="272"
Height="168"
Background="#FF2D3F81"
RenderTransformOrigin="0.0,0.0"
MouseLeftButtonDown="resize"
>
<
Canvas.RenderTransform>
<
ScaleTransform
x:Name="scale"
ScaleX="1"
ScaleY="1"
/>
</
Canvas.RenderTransform>
<
Rectangle
Fill="#FFFF1919"
Stroke="#FFFFFFFF"
Width="72"
Height="32"
Canvas.Left="32"
Canvas.Top="24"
/>
<
Ellipse
Fill="#FFDB6969"
Width="40"
Height="40"
Canvas.Left="136"
Canvas.Top="88"
/>
<
Path
Fill="#FFFFFFFF"
Stretch="Fill"
Stroke="#FF000000"
Width="65"
Height="1"
Canvas.Left="199.5"
Canvas.Top="149.5"
Data="M320,248 L384,248"
/>
</
Canvas>
</
Canvas>

JavaScript - Method #1: Manual Resize:
var resizeBy = 1.1;

function resize(sender, args) {

var canvas = sender.findName("CanvasToResize");

for (var i=0; i<canvas.children.count; i++) {

var child = canvas.children.getItem(i);

child.Width = child.Width*resizeBy;
child.Height = child.Height*resizeBy;

var top = child.getValue("Canvas.Top");
var left = child.getValue("Canvas.Left");

child.setValue("Canvas.Top", top*resizeBy);
child.setValue("Canvas.Left", left*resizeBy);
}

canvas.Width = canvas.Width*resizeBy;
canvas.Height = canvas.Height*resizeBy;
}

JavaScript - Method #2: Scale to Resize
var resizeBy = 1.1;

function resize(sender, args) {

var st = sender.findName("scale");

var scaleX = st.getValue("ScaleX");
var scaleY = st.getValue("ScaleY");

st.setValue("ScaleX", scaleX*resizeBy);
st.setValue("ScaleY", scaleY*resizeBy);
}