2

I understand that there are a variety of ways to size child elements according to parent elements. If you're using a grid for example, you can use row and column definitions and you get lots of freedom regarding automatic sizes or fixed sizes or "star" sizes. However, if the child elements themselves have a fixed width and height then it won't matter if the parent tells the child to fill all available space. The child element will remain the same size.

I have a window that was designed to always display its contents at the same pixel dimensions no matter what size the window is resized to. Rather than go and change every single child element in every XAML page so that it doesn't have a fixed size, I'd like to get the main Grid to just scale to fit the window. So far the only way to get elements with fixed dimensions to display at different sizes is to use Transform scaling, either with a RenderTransform or a LayoutTransform. But if I go that route, I'll have to code the scaling in C# to respond to resizing events rather than have it happen automatically. Is there some native builtin way to do this in XAML? This feels like the kind of thing I should be able to do with some special property, or perhaps a ContentControl or ContentPresenter.

I've seen Resize WPF Window and contents depening on screen resolution but it's asking about conventional resizing and not scaling fixed elements. I've also seen How to make all controls resize accordingly proportionally when window is maximized? and that has the same problem though the second answer at least talks about handling resizing events.

Here's a simplified example of a fixed-dimension child element not resizing as desired:

<Window x:Class="WpfTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="Window1" Height="200" Width="300" Background="LightBlue">
    <Grid>
        <Frame Background="Blue" Width="200" Height="100">

        </Frame>
    </Grid>
</Window>

Actual results:

Blue rectangle that's always the same size

Desired results:

Blue rectangle that scales to fill its window

As you can see, what I'm looking for is a sort of letterboxing effect, meaning I want the aspect ratio to be maintained. However, I haven't found a way to get automatic scaling even without worrying about the aspect ratio, so I thought I'd consider the letterboxing as a sort of second phase that I'd worry about later.

Kyle Delaney
  • 11,616
  • 6
  • 39
  • 66

2 Answers2

7

The control you are looking for is a Viewbox. It grows to fill its container (you can set the stretch style for the letterboxing) and scales all its contents accordingly. Just make it the root element of your application (or whatever you want stretched):

<Viewbox>
    <Grid> //Or whatever
         <OtherStuff>
    </Grid>
</Viewbox>

Note that because the viewbox is scaling its contents traditional Grid behavior and similar will stop working since the size of the content never actually changes.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • This is great! I will most likely mark this as correct but I usually wait a day or so to give other people a chance. I do have one minor question, though. Is there a way to control what goes in the margins, as though the main `Viewbox` content is taking up column 1 and I want a simple gradient image to go in columns 0 and 2? – Kyle Delaney May 25 '18 at 20:57
  • @KyleDelaney Maybe not as cleanly as you suggest; but the viewbox is a control like any other. You could put your image as the background of your `Window` for example and it would appear in the "margins" – BradleyDotNET May 25 '18 at 21:17
  • Okay, I guess this is getting complicated, but if I put the Viewbox in an auto column of a Grid between two star columns, it behaves as desired but only for margins on the left and right. When the X dimension isn't wide enough it gets cut off. – Kyle Delaney May 26 '18 at 01:36
  • @KyleDelaney Throw some * rows in as well? Not really sure what you need/are looking for there – BradleyDotNET May 26 '18 at 05:50
  • Okay, I got it. The `Viewbox` is in an auto column between two * columns like I said. The three-column `Grid` is then placed in another `Viewbox` which makes it shrink when the window gets too narrow. – Kyle Delaney May 27 '18 at 21:46
  • No wait, that still doesn't work. The outer Viewbox seems to collapse the * columns. – Kyle Delaney May 27 '18 at 23:14
-1

Another option is to use a MultiValueConverter to set the height and width. You could give the Converter the ActualWidth and ActualHeight of the root container als parameters and let it calculate the needed aspect ratio.

A tutorial which describes the MultiValueConverter: http://www.wpftricks.com/2017/05/wpf-multivalueconverter.html

kphil80
  • 35
  • 4
  • 2
    While technically true; this is way overcomplicated for a problem that has a ready made solution. It also doesn't solve the problem of scaling contents – BradleyDotNET May 25 '18 at 21:18