On the past MVP Summit, on which I assisted as an ASP.Net MVP (curiously my activity last year has been mostly of WPF and Silverlight talks) I commented the need of having the WPF Viewbox control on Silverlight 2.0… Silly of me I didn’t realized that I could do it myself as it’s pretty easy to subclass or define user controls for this new version, fortunately my seat companion and one of the main Spain WPF & Silverlight experts, Miguel Jimenez, told me “Hey, why don’t you make it yourself?” And well, he was absolutely right, so here it is… at least a preliminary version of it that more or less does the work I need done.
I basically inherited from the Canvas panel (first tried from the panel base class, but realized it would be easier through Canvas subclassing). Then I wanted it to scale its contents when its allowed space (width and height) grows up or down. Then I added dynamically a ScaleTransform and a TranslateTransform on it’s constructor, added them to a TransformGroup and added it to the Class RenderTransform property (inherited from Canvas).
this.ST_scale = new ScaleTransform();
this.TF_offset = new TranslateTransform();
//We add a transform with the Scale and Translate Transforms…
TransformGroup tg_transformViewbox = new TransformGroup();
//We add this Transform to the ViewBox (Subclassed from the Canvas class)
this.RenderTransform = tg_transformViewbox;
Then the only thing left to it was to implement an override for the ArrangeOverride function (more info here: http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.arrangeoverride(VS.95).aspx ).
There I determine the scale ratio, choosing the minimum ratio from the X and Y calculated ratios. Also I adjust the offset for the Y or X axis, to adjust more properly the positioning.
protected override Size ArrangeOverride(Size finalSize)
//We scale the contents based on the desired size width and height.
double scaleX = finalSize.Width / this.DesiredSize.Width;
double scaleY = finalSize.Height / this.DesiredSize.Height;
//By default we only allow an “uniform” Stretch attribute option.. we could add the attribute and held the logic in this function.
// To do this more seriously, we should also add the StretchDirection and Stretch properties too.
if (scaleX > scaleY)
//Lowest scale ratio wins (Y axis is lower)
this.ST_scale.ScaleX = scaleY;
this.ST_scale.ScaleY = scaleY;
this.TF_offset.X = (finalSize.Width – this.DesiredSize.Width * scaleY) / 2;
this.TF_offset.Y = 0;
//Lowest scale ratio wins (X axis is lower)
this.ST_scale.ScaleX = scaleX;
this.ST_scale.ScaleY = scaleX;
this.TF_offset.Y = (finalSize.Height – this.DesiredSize.Height * scaleX) / 2;
this.TF_offset.X = 0;
And this is all is there to it… I didn’t needed to override the MeasureOverride (check http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.measureoverride(VS.95).aspx). Also if you want to know more about creating custom panels, there are some things to read:
The code has been uploaded here: <<<viewboxzip>>> but has a small problem that I realized afterwards.
As a small notice, this code is licensed under MS-PL (http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx).
This problem is that the “original” WPF Viewbox only allows one control and this one is a Canvas so it allows multiple controls positioned together, so it resizes all accordingly, including the layout, which is respected.
Anyway this is the behavior I wanted to obtain, but it is not the WPF Viewbox behavior, so it’s not Ok… for a WPF Viewbox to do this I should put a Canvas inside the Viewbox and then the controls inside the Canvas.
Hope you have fun with it. 😉
The link for the source code donwload is here: viewboxzip