Search code examples
wpfviewbox

Making a Viewbox scale vertically but stretch horizontally


I want to make a Viewbox (or something similar) that scales only its height, and then stretches its content horizontally.

If I do this:

<Viewbox>
  <StackPanel>
    <Button>Foo</Button>
    <Button>Bar</Button>
  </StackPanel>
</Viewbox>

then I get this:


(source: excastle.com)

It acts as if both of the buttons had HorizontalAlignment="Center", and then scales the result. But I don't want HorizontalAlignment="Center"; I want HorizontalAlignment="Stretch", like this:


(source: excastle.com)

So, I want it to read its contents' desired height, calculate a scaling factor based only on the height, and then allow the scaled content to stretch horizontally.

Is there any way to accomplish this using the Viewbox, and/or some third-party panel?


Solution

  • There is no such control include with WPF but you can write one yourself without too much trouble. Here is a custom ViewboxPanel that has your specifications:

    public class ViewboxPanel : Panel
    {
        private double scale;
    
        protected override Size MeasureOverride(Size availableSize)
        {
            double height = 0;
            Size unlimitedSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
            foreach (UIElement child in Children)
            {
                child.Measure(unlimitedSize);
                height += child.DesiredSize.Height;
            }
            scale = availableSize.Height / height;
    
            return availableSize;
        }
    
        protected override Size ArrangeOverride(Size finalSize)
        {
            Transform scaleTransform = new ScaleTransform(scale, scale);
            double height = 0;
            foreach (UIElement child in Children)
            {
                child.RenderTransform = scaleTransform;
                child.Arrange(new Rect(new Point(0, scale * height), new Size(finalSize.Width / scale, child.DesiredSize.Height)));
                height += child.DesiredSize.Height;
            }
    
            return finalSize;
        }
    }
    

    and you use it like this:

    <local:ViewboxPanel>
        <Button>Foo</Button>
        <Button>Bar</Button>
    </local:ViewboxPanel>
    

    It definitely needs some work but this might get you started.