简体   繁体   中英

Change font size if the text exceeds the boundary of Textblock

I have a textblock with a dimension of Width=511, Height=159. FontSize=28. I want to change the font size if the text exceeds the dimension of the textblock so that all the text will be displayed. Is there a way of doing this? A formula maybe?

This solution implies the use of a ViewBox, i think that with Wpf transforming features there is no need to change the font size of the text, Almost the same result can be archieved using transformation (and a ViewBox in this case).

Instead of putting your TextBlock inside a ViewBox, modify it's template and put the control where the text appears inside a ViewBox, something like:

<ControlTemplate TargetType="{x:Type TextBox}">                     
    <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
        <Viewbox HorizontalAlignment="Left">
            <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
        </Viewbox>
    </Microsoft_Windows_Themes:ListBoxChrome>

    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Now you get a control that sizes it's text to fit in the available spacee, thanks WPF.

Also here is some example

文字示例

I'm not really sure about WPF, but in WinForms you could use MeasureString method, to measure strings dimensions in a given font. So, whenever the contents of the textblock changes, you just need to use this method and if the dimensions of the text are bigger then the dimensions of the text block - reduce the font size and measure again.

(now, after I've written this, I think there should be a simpler method for this)

It depends on what font face you use, for instance, Courier New is designed to have each character the same width, so if you do research about what the width per character is you can use the get length function for the string(giving you the length in characters) and from there calculate its width in pixels. If its width exceeds 511px the you adjust the size accordingly.

If you use a different font like Arial, you can do the same and if you really want it accurate, you can group the alphabet into narrow letters, like 'i', 'l' etc. and medium letters like 't' and fat letters like 'o' and the capitals. Then you get the number of narrow, medium and fat letters and calculate the size from that data, but personally, that's too much for me.

Hope this was helpful.

Edit: Ignore this one, I just read about the measurestring function, It's a much smaller effort than my suggestion.

Here's what I came up with. Be sure you handle the -1.0 font size case.

      private static double GetFontSize(TextBox textBox)
      {
         double fontSize = textBox.FontSize;
         FormattedText ft = new FormattedText(textBox.Text, CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight,
                                          new Typeface(textBox.FontFamily, textBox.FontStyle, textBox.FontWeight, textBox.FontStretch),
                                          fontSize, textBox.Foreground);
         while (textBox.Width < ft.Width)
         {
            fontSize -= 1;
            if (fontSize < 0) return -1.0;
            ft = new FormattedText(textBox.Text, CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight,
                                                      new Typeface(textBox.FontFamily, textBox.FontStyle, textBox.FontWeight, textBox.FontStretch),
                                                      fontSize, textBox.Foreground);
         }

         return fontSize;
      }

Edit: I should look at the tags before posting. No clue what WPF might have to offer to solve this.

I don't have any proof to back this up, but it seems that (also for variable-width fonts, at least all the ones installed on my machine):

  • Font size has a linear relationship with the width of a given string
  • Font size 0 results in a width of 0

This means you could probably use MeasureString once on the largest font size allowed, and then interpolate to find the optimal font size.

There are some "pixel bumps" on that "linear road" though, so you could be a few pixels off - but it's a good alternative from the measure-loops.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM