cnd
cnd

Reputation: 33784

Is it possible to make fonts scaleable?

All my grids could be small and very big depending on window size but text inside is looking really small on big grid sizes.

My current idea (but I don't know how to realize it yet) is to make Binding for all Grid elements to single font and then change the font size by

override void OnRender(DrawingContext dc) {

depending on window size.

The question is: Is this idea sane and is there other methods for it?

Upvotes: 1

Views: 197

Answers (3)

xBiznitch
xBiznitch

Reputation: 1

I know this is an old post but it was one of the first things to come up when I searched for the topic, so here is my solution:

I've done this in a project recently for work with text boxes and scaling their content font size relative to the screen. For this I set up an integer value and had font size bound to it.

In my case, my screen height starts at 800x650 and I wanted my font to be size 12 by default so I set the integer value (_ScaledFontSize) to WindowHeight/(650/12).

Everytime the screen size changes, a function is called to recalculate the font size and a property change event is called. This function is where you can add constraints for minimum and maximum font sizes using something simple like:

//Set a minimum font size
if(_ScaledFontSize < 12)
    _ScaledFontSize = 12;

In order to enforce this scaled sized, every control that you want to scaled font size on must be bound to the ScaledFontSize property.

Final Result:

Text at application launch

Text at about 1920x1080 (Slightly smaller because not fullscreen)

I was struggling to find something like this for a while and in the end this is what I went with. Luckily the code is pretty simple: MainWindow.xaml.cs:

using System.Windows;
using System.ComponentModel;

namespace FontScaling
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        private int _ScaledFontSize;

        public int ScaledFontSize
        {
            get => _ScaledFontSize;
            set => _ScaledFontSize = value;
        }

        public void PropChange(string name)
        {
            System.ComponentModel.PropertyChangedEventArgs propertyChangedEvt = new System.ComponentModel.PropertyChangedEventArgs(name);

            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, propertyChangedEvt);
            }

        }
        public MainWindow()
        {
            InitializeComponent();
            _ScaledFontSize = (int)Application.Current.MainWindow.Height / 54;
        }

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _ScaledFontSize = (int)Application.Current.MainWindow.ActualHeight / 54;
            PropChange("ScaledFontSize");
        }
    }
}

MainWindow.xaml:

<Window x:Class="FontScaling.MainWindow"
        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"
        xmlns:local="clr-namespace:FontScaling"
        mc:Ignorable="d"
        Title="MainWindow" Height="650" Width="800"
        SizeChanged="Window_SizeChanged"
        Name="_This">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="200*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="15*"/>
            <ColumnDefinition Width="10*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="10*"/>
            <ColumnDefinition Width="15*"/>
        </Grid.ColumnDefinitions>

        <TextBlock 
            VerticalAlignment="Bottom"
            Grid.Row="1"
            Grid.Column="1"
            Text="Non Scaled TextBlock"/>
        <TextBox 
            Grid.Row="2"
            Grid.Column="1" 
            Text="Non Scaled Text"/>

        <TextBlock
            VerticalAlignment="Bottom"
            Grid.Row="1"
            Grid.Column="3" 
            Text="Scaled TextBlock"
            FontSize="{Binding ScaledFontSize, ElementName=_This}"/>
        <TextBox 
            Grid.Row="2" 
            Grid.Column="3" 
            Text="Scaled TextBox"
            FontSize="{Binding ScaledFontSize, ElementName=_This}"/>
    </Grid>
</Window>

Upvotes: 0

pluka
pluka

Reputation: 125

I like more this solution as suggested by roberther. It is more aesy and clean.

<Viewbox>
    <TextBlock Text="Hello World" />
</Viewbox>

Upvotes: 0

Moha Dehghan
Moha Dehghan

Reputation: 18472

If you have not set the font on inner elements explicitly, they inherit the parent font. So you can change the font size on one of the parent elements (for example the Window itself or the Grid). This changes the font size on all inner elements that has not specified the font size explicitly.

However if your font should be of different sizes, the best solution in my opinion is binding the font size of elements to the font size of the parent window, and using a value converter to do a scale on the font size:

Define a value converter like this:

using System;
using System.Windows.Data;

namespace WPFTest
{
    public class FontSizeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return null;
            double windowFontSize = (double)value;
            var scale = System.Convert.ToDouble(parameter);
            return windowFontSize * scale;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

And use it in your xaml:

<Window x:Class="WPFTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:test="clr-namespace:WPFTest"
        Title="Window1" Height="300" Width="300" FontSize="20" x:Name="window1">
    <Window.Resources>
        <test:FontSizeConverter x:Key="fontSizeConverter"/>
    </Window.Resources>
    <Grid>
        <StackPanel Grid.Row="0" Grid.Column="0">
            <TextBlock
                FontSize="{Binding ElementName=window1, Path=FontSize, Converter={StaticResource ResourceKey=fontSizeConverter}, ConverterParameter=1.5}">
                Text 1
            </TextBlock>
            <TextBlock FontSize="{Binding ElementName=window1, Path=FontSize, Converter={StaticResource ResourceKey=fontSizeConverter}, ConverterParameter=0.7}">
                Text 2
            </TextBlock>
            <TextBlock >Text 3</TextBlock>
        </StackPanel>
    </Grid>
</Window>

ConverterParameter is used as the scale of the element's font related to the window (specified in ElementName property of the binding).

In this example font of the first TextBlock is 150% of the window font and font of the second TextBlock is 70% of the window. The third TextBlock follows the font size of the window.

Upvotes: 1

Related Questions