2

There is method MeasureString in Graphics class, which helps user to find out, what size string has for specified font. But what if I want to know opposite - pick proper font size to fit text to width?

Actual use-case: I have multiple TextBlocks, which should have same font size. I'd like to reduce size of text of all blocks, if width of any TextBlock content exceeds certain value (for example, width of TextBlock and some margin). For now, I'm using MeasureString, to calculate some multiplier, which affects font size, but it seems, that it works not as I wanted it to - it leaves way too big gaps.

For example, I have limit of width 75 px, default font size 13, and string with width 125 px. (75/125) * 13 gives me 7.8 font size, which causes string to have 52 px in width (way much smaller than 75).

So, any good ways to do this?

Code In ViewModel:

private int _defaultFontSize = 13;
private int _maxStringSize = 75;
private string _text = "MoreMoreMore"; //test text, which exceeds 75 px

public double NameFontSize
{
    get
    {
        var font = new Font("Segoe UI Light", _defaultNameFontSize);
        double size;
        using (var graphics = Graphics.FromImage(new Bitmap(1, 1)))
        {
            size = graphics.MeasureString(_text, font);
        }

        return Math.Min(1, _maxStringSize/size) * _defaultFontSize;
    }
}

public string Text
{
    get { return _text; }
}

In XAML

<TextBlock Text = "{Binding Text}" FontSize = "{Binding NameFontSize}"/>
lentinant
  • 792
  • 1
  • 10
  • 36
  • Can you show related code? The idea with scaling is correct approach (this is what TTF meant for). – Sinatr Feb 10 '16 at 11:06
  • @Sinatr Added example code (it's doing literally what I've described). Problem is, that I seek method, which will give in result not ~50 px width, but more to 70 px. It seems, that font scaling is not very precise. – lentinant Feb 10 '16 at 11:17
  • See [measuring text](http://stackoverflow.com/q/632445/1997232) in wpf. Maybe you are not measuring *correct* size with your method. I am not sure if `MeasureString` (gdi+) can be used to calculate wpf `FontSize`. – Sinatr Feb 10 '16 at 11:28
  • Yeah, I've got it already. Now I'm working on much nastier method to get string width, since WPF doesn't allow to directly push readonly properties to VM. – lentinant Feb 10 '16 at 13:21

2 Answers2

1

What about putting the TextBlock inside a ViewBox and let that take care of the scaling?

<Viewbox Width="75">
    <TextBlock Text="{Binding Text}"/>
</Viewbox>
larsbw
  • 61
  • 4
1

You're measuring with different font size units.

The System.Drawing.Font constructor takes an em-size in points, which are 1/72 of an inch

emSize: ... The em-size, in points, of the new font.

while TextBlock.FontSize is given in WPF units, which are 1/96 inch:

... An unqualified value is measured in device independent pixels. ...

Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Yeah, it seems so. I had to apply different approach - use ActualWidth instead of one found by MeasureString. Which led me to different problem - getting read-only properties of controls in view-model (MVVM). Anyway, solved, thanks. – lentinant Feb 10 '16 at 13:31