-2

I have a label like this:

 <Grid Name="grid_footer" Grid.Row="2" ShowGridLines="True">
                <Grid.RowDefinitions>
                    <RowDefinition Height="3.4*" />
                    <RowDefinition Name="row_text" Height="3.2*" />
                    <RowDefinition Height="3.4*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.38*" />
                    <ColumnDefinition Width="9.62*" />
                </Grid.ColumnDefinitions>

                <!-- project location label -->
                <Label  Name ="FileLocationLabel" Content="TEST"  Foreground="Black" Background="Beige" FontWeight="Bold" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1"  Grid.RowSpan="1" HorizontalAlignment="Left" Padding="0" FontSize="{Binding ElementName=row_text, Path=ActualHeight}"/>


            </Grid>

enter image description here

As you can see, there is still some unwanted padding on the bottom and I have tried almost everything to remove it but I couldn't. I simply want the font to stretch from top to bottom of the row.

Ivan
  • 1,081
  • 2
  • 17
  • 43
  • [Use a TextBlock instead of a Label](https://stackoverflow.com/q/11501380/1136211). – Clemens Aug 30 '17 at 09:51
  • @Clemens I already tried it, but it is the same thing. – Ivan Aug 30 '17 at 09:52
  • Then probably don't set `VerticalAlignment="Stretch"` – Clemens Aug 30 '17 at 09:54
  • @Clemens I already tried all those combinations, but it was still the same. – Ivan Aug 30 '17 at 09:55
  • That is padding of font height and baseline offset, you can't just remove it without side effects of invisible accents of some letters – Mitya Aug 30 '17 at 10:46
  • The correct font size and the spacing around letters depends on the actual font among other things. – grek40 Aug 30 '17 at 10:52
  • 1
    @Ivan updated my answer with some more accurate result. I don't know whether you actually need this detailed scaling, but I feel like it really answers the question now :) – grek40 Aug 30 '17 at 16:49

2 Answers2

2

For starters, try the following:

  • Wrap your text in a container in order to get ActualHeight, because that's not comming from a RowDefinition
  • Add TextBlock.LineHeight and TextBlock.LineStackingStrategy settings to the label (taken idea from https://stackoverflow.com/a/7568216/5265292)
  • Experiment with different fonts... for example, when I set FontFamily="Arial", I get different spacing details than with the default font.

.

<Border
    x:Name="container1"
    Grid.Row="1" Grid.Column="1"
    VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Padding="0" Margin="0" BorderThickness="0">
    <Label
        Name ="FileLocationLabel"
        Content="TESTg"
        Foreground="Black" Background="Beige"
        FontWeight="Bold"
        HorizontalAlignment="Left"
        Padding="0" Margin="0"
        TextBlock.LineHeight="{Binding ElementName=container1,Path=ActualHeight}"
        TextBlock.LineStackingStrategy="BlockLineHeight"
        FontSize="{Binding ElementName=container1,Path=ActualHeight}"/>
</Border>

If you need more exact font sizing, you may want to compute the actual text size for specific font settings, similar to this answer https://stackoverflow.com/a/15982149/5265292

Note I added a "g" to the test content because it is using the lower part of text space, that would stay unused with "TEST"


I decided to take a closer look at the problem and came up with the following converter to determine a font size and lineheight in order to support different texts and fonts.

/// <summary>
/// Values:
/// - text to be rendered
/// - available height
/// - framework element with values for fontfamily etc
/// 
/// By default, returns a font size for a given text to fit into available height
/// With parameter = "lineheight", produces the lineheight for a given text and font size
/// </summary>
public class FontSizeProvider : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string text = values[0] as string;
        double height = System.Convert.ToDouble(values[1]);
        FrameworkElement f = values[2] as FrameworkElement;

        if (height <= 0.0)
        {
            height = 10;
        }

        var param = parameter as string;

        // (1) in order to compute the LineHeight, take the font size, produce formatted text
        //   and determine the LineHeight based on available space and the size of text below the baseline
        // (2) in order to compute the fontsize, take the container height, produce formatted text
        //   and scale the font depending on the actual text size
        double fsize = param == "lineheight" ? TextBlock.GetFontSize(f) : height;

        FontFamily family = TextBlock.GetFontFamily(f);
        FontStyle style = TextBlock.GetFontStyle(f);
        FontWeight weight = TextBlock.GetFontWeight(f);
        FontStretch stretch = TextBlock.GetFontStretch(f);

        // produce the formatted text
        var formattedText = new FormattedText(text, culture,
            f.FlowDirection,
            new Typeface(family, style, weight, stretch),
            fsize, Brushes.Black);

        // get the result
        if (param == "lineheight")
        {
            var afterBaseline = formattedText.Height - formattedText.Baseline + formattedText.OverhangAfter;
            // for some reason, the desired line height needs to be scaled according to the font family line sizes
            var scalingFactor = family.LineSpacing / family.Baseline;
            var lineHeightResult = (height - afterBaseline) * scalingFactor;
            return System.Convert.ChangeType(lineHeightResult, targetType);
        }
        else
        {
            var fontSizeResult = height * height / formattedText.Extent;
            return System.Convert.ChangeType(fontSizeResult, targetType);
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Instance in resources:

<local:FontSizeProvider x:Key="fontSizeProvider"/>

Usage:

<Border x:Name="container1"
        Grid.Row="1" Grid.Column="1"
        VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
        Padding="0" Margin="0" BorderThickness="0">

    <Label
        Content="TÉ"
        Foreground="Black" Background="Beige"
        HorizontalAlignment="Left"
        Padding="0" Margin="0"
        TextBlock.LineStackingStrategy="BlockLineHeight">
        <Label.FontSize>
            <MultiBinding Converter="{StaticResource fontSizeProvider}">
                <Binding RelativeSource="{RelativeSource Self}" Path="Content"/>
                <Binding ElementName="container1" Path="ActualHeight"/>
                <Binding RelativeSource="{RelativeSource Self}"/>
            </MultiBinding>
        </Label.FontSize>
        <TextBlock.LineHeight>
            <MultiBinding Converter="{StaticResource fontSizeProvider}" ConverterParameter="lineheight">
                <Binding RelativeSource="{RelativeSource Self}" Path="Content"/>
                <Binding ElementName="container1" Path="ActualHeight"/>
                <Binding RelativeSource="{RelativeSource Self}"/>
            </MultiBinding>
        </TextBlock.LineHeight>
    </Label>

</Border>

The font size is scaled so that the actual text with the actual font is enlarged to fill the height of the container. This means, for the same container height, the font size will be different between text "Ég" (smaller font, since text is using much height) and "ace" (larger font since all letters are small height).

At computing the LineHeight I ran into a strange problem: I had to multiply the available height by 1.22 (for Segoe UI font) in order to make the baseline of text appear at the bottom of the available space. This didn't really work for some other fonts. After some testing I found out that the right scaling factor per font is given by fontfamily.LineSpacing / fontfamily.Baseline.

With the scaling factor problem solved, the approach is pretty straight forward: compute the height of text that is rendered below the baseline and adjust the lineheight according to text height minus the extra space below.

grek40
  • 13,113
  • 1
  • 24
  • 50
-1

Try to use ViewBox to stretch your Label

<Viewbox Grid.Row="1" Grid.Column="1"  StretchDirection="Both" Stretch="Uniform" HorizontalAlignment="Left">
        <Label Name ="FileLocationLabel" Content="TEST"
                   Foreground="Black" Background="Beige" FontWeight="Bold"
                   HorizontalAlignment="Left" VerticalAlignment="Stretch"  Padding="0"/>
</Viewbox>
Mitya
  • 632
  • 5
  • 18