Search code examples
wpfxamluwpcontrols

Automatic resizing of only the font of a wpf control


I've got a grid layout that looks like this:

this.

This is its code:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="2.5*"/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition Height="2.5*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2.5*"/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition Width="2.5*"/>
    </Grid.ColumnDefinitions>

    <TextBox x:Name="username" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Text="Username"
                    GotFocus="RemoveLabel" LostFocus="RestoreLabel"
                    HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
    <TextBox x:Name="password" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Text="Password"
                GotFocus="RemoveLabel" LostFocus="RestoreLabel"
                HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
    <Button x:Name="signUp" Grid.Row="5" Grid.Column="1" Content="Sign up"/>
    <Button x:Name="signIn" Grid.Row="5" Grid.Column="3" Content="Sign in"/>
</Grid>

This behavior is desired:

This

The only thing that is missing is on screen resize for the text in each control to also resize to utilize the free space in that control.

I tried using Viewbox, but regardless of the value of the Stretch property, it changes the size of the control and I don't know how to force it to remain sized according to the grid.

I primarily looked for answers on this post: How to automatically scale font size for a group of controls?


Solution

  • There is a SizeChanged routed event that as the name implies is triggered every time a control changes it's size. So you can add a routed event handler(method) that listens for everytime the control's size is changed and changes its font size or any property for that matter.

    Here's an implementation for the specific case:

    private void ResizeFont(object sender, SizeChangedEventArgs e)
    {
        var control = sender as Control;
        if (control == null) return;
        control.FontSize = control.ActualHeight / 2;
    }
    

    In the xaml you just need to add the SizeChanged property to the controls:

    <TextBox x:Name="username" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Text="Username"
            GotFocus="RemoveLabel" LostFocus="RestoreLabel"
            HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
            SizeChanged="ResizeFont"/>
    <TextBox x:Name="password" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Text="Password"
            GotFocus="RemoveLabel" LostFocus="RestoreLabel"
            HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
            SizeChanged="ResizeFont"/>
    <Button x:Name="signUp" Grid.Row="5" Grid.Column="1" Content="Sign up" SizeChanged="ResizeFont"/>
    <Button x:Name="signIn" Grid.Row="5" Grid.Column="3" Content="Sign in" SizeChanged="ResizeFont"/>
    

    This works nicely for buttons and text boxes with a wide aspect ratio that have a single line of text (text blocks adapt their height to the font size, so it doesn't work for them). If you need some different behavior this method is also easy to modify, for example when using a TextBox with multiple lines you can change the font size to be based on the ActualWidth instead of ActualHeight.

    This is the result in the specific case. enter image description here