9

I have a WPF application where the user interface should be scaled so that it should become larger if the windows is made larger. In one of the dialogs, I need to present a list of items to a user and the user should click one of them. The list will contain from 1 to around 15-20 items. I want the font size for each individual item to be as big as the font size for the other items in the list, but at the same time I want the font size to increase if the window is made larger.

At the moment, my test code looks like below.

<Window x:Class="WpfApplication4.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:WpfApplication4"
    Title="Window1" Height="480" Width="640">


    <ScrollViewer>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30*" MinHeight="30"/>
                <RowDefinition Height="30*" MinHeight="30"/>
                <RowDefinition Height="30*" MinHeight="30"/>
            </Grid.RowDefinitions>

            <Button Grid.Row="0" MaxHeight="100"><Viewbox><TextBlock>T</TextBlock></Viewbox></Button>
            <Button Grid.Row="1" MaxHeight="100"><Viewbox><TextBlock>Test</TextBlock></Viewbox></Button>
            <Button Grid.Row="2" MaxHeight="100"><Viewbox><TextBlock>Test Longer String</TextBlock></Viewbox></Button>

        </Grid>

    </ScrollViewer>

</Window>

If the application is started and the Window is made wide, everything looks OK. If the window width is decreased, the font size of the text Test Longer String is made smaller, but the font size for T and Test remains the same. I do understand why this happens - the viewbox will scale the contents to its maximum size. What I want to know is what method I should use to solve this problem.

I don't want to give the controls specific font sizes because some people will run this on low-resolution screens such as 640x480 and others will use larger widescreens.

EDIT:

I've tried to modify my code to the following:

<ScrollViewer>
    <Viewbox>
        <ItemsControl>
            <Button>Test 2</Button>
            <Button>Test 3</Button>
            <Button>Test 4 afdsfdsa fds afdsaf</Button>
            <Button>Test 5</Button>
            <Button>Test 5</Button>
            <Button>Test 5</Button>
            <Button>Test 5</Button>
            <Button>Test 5</Button>
        </ItemsControl>
    </Viewbox>
</ScrollViewer>

But with the size of the button borders are increased as well, so on large screens, the button borders become a centimeter wide.

Martin
  • 227
  • 3
  • 6

5 Answers5

0

Try this: Render your text items like you would do it any other time:

  • TextBlocks contained in an 'ItemsControl'?
  • ListBox?

Place the whole shebang into a ViewBox and set it to scale appropriate to your needs. Look for Horizontal, Vertical or combined scaling properties.

Pieter Breed
  • 5,579
  • 5
  • 44
  • 60
  • I've updated my post. See under "Edit". In short, if I use a TextBlock rather than a Button, I loose the "Button"-user interface (click-effect and so on). If I use a Button and place that inside of a Viewbox, the entire button - including its border - will be resized. I don't want a 1cm button border just because the program is maximized. – Martin Nov 10 '09 at 12:28
0

This workaround might help:

    <ScrollViewer>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30*" MinHeight="30"/>
            <RowDefinition Height="30*" MinHeight="30"/>
            <RowDefinition Height="30*" MinHeight="30"/>
        </Grid.RowDefinitions>

        <Button Grid.Row="0" MaxHeight="100">
            <Viewbox>
                <TextBlock Width="{Binding ElementName=tbLonger,Path=ActualWidth}">T</TextBlock>
            </Viewbox>
        </Button>
        <Button Grid.Row="1" MaxHeight="100">
            <Viewbox>
                <TextBlock Width="{Binding ElementName=tbLonger,Path=ActualWidth}">Test</TextBlock>
            </Viewbox>
        </Button>
        <Button Grid.Row="2" MaxHeight="100">
            <Viewbox>
                <TextBlock Name="tbLonger">Test Longer String</TextBlock>
            </Viewbox>
        </Button>
    </Grid>
</ScrollViewer>

The key is to set all textblocks the same width. In this case they all follow the longest textblock through binding.

Jojo Sardez
  • 8,400
  • 3
  • 27
  • 38
  • I believe OP's code doesnt have a problem with the width of the buttons, they are all the same length when the window becomes smaller, but he wants the fontsize to be the same (or thats what I imply). So, the binding should be with the fontsize of the longest text. – Ricardo Olivo Poletti Nov 17 '16 at 13:13
0

I had to make an resolution independent application and made it with this answer here: tips on developing resolution independent application

with that your application is scaling (or zooming), depending on the resolution.

el-nino
  • 399
  • 9
  • 26
0

If you only want the FontSize to change then bind it to your MainWindow ActualWidth (say) and use a converter to scale:

<Window.FontSize>
    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" ConverterParameter="20">
        <Binding.Converter>
            <local:ScaleConverter />
        </Binding.Converter>
    </Binding>
</Window.FontSize>

The converter parameter is how you set the font size at some arbitrary width size (1000 pixels, say), which your converter will then also take into account:

internal class ScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Double.Parse(parameter.ToString()) * (double)value / 1000;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}
Mark Feldman
  • 15,731
  • 3
  • 31
  • 58
-1

The simplest way is probably to construct a decorator to do the job. You might call it "VerticalStretchDecorator" or something like that.

Here is how it would be used:

<UniformGrid Rows="3" MaxHeight="300">
  <Button>
    <my:VerticalStretchDecorator>
      <TextBlock>T</TextBlock>
    </my:VerticalStretchDecorator>
  </Button> 
  <Button>
    <my:VerticalStretchDecorator>
      <TextBlock>Test</TextBlock>
    </my:VerticalStretchDecorator>
  </Button> 
  <Button>
    <my:VerticalStretchDecorator>
      <TextBlock>Test Longer String</TextBlock>
    </my:VerticalStretchDecorator>
  </Button>
</UniformGrid>

I used UniformGrid instead of Grid, but it would work the same way with Grid.

It would be implemented something like this:

public class VerticalStretchDecorator : Decorator
{
  protected override Size MeasureOverride(Size constraint)
  {
    var desired = base.Measure(constraint);
    if(desired.Height > constraint.Height || desired.Height==0)
      LayoutTransform = null;
    else
    {
      var scale = constraint.Height / desired.Height;
      LayoutTransform = new ScaleTransform(scale, scale); // Stretch in both directions
    }
  }
}
Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • This code doesn't compile whatsoever. Measure() returns void and there is no return value from MeasureOverride() – Bob Sep 21 '11 at 17:36