如何为所有字体权重设置相同大小的WPF TextBlock?

时间:2013-12-12 23:25:48

标签: wpf textblock

我会跳到追逐:有没有办法告诉WPF TextBlock衡量自己,以便当其FontWeight更改时其大小不会改变?

我有TextBlock根据样式动态更改字体权重。 TextBlock位于RadioButton内,因此在选中时为粗体,否则为正常:

<Style x:Key="BoldWhenChecked" TargetType="RadioButton">
    <Style.Triggers>
        <Trigger Property="IsChecked" Value="True">
            <Setter Property="TextElement.FontWeight" Value="Bold" />
        </Trigger>
    </Style.Triggers>
</Style

以下是单选按钮本身:

<StackPanel Orientation="Horizontal">
    <RadioButton Style="{StaticResource BoldWhenChecked}">
        <TextBlock Text="Item 1" />
    </RadioButton>
    <RadioButton Style="{StaticResource BoldWhenChecked}">
        <TextBlock Text="Item 2" />
    </RadioButton>
    <RadioButton Style="{StaticResource BoldWhenChecked}">
        <TextBlock Text="Item 3" />
    </RadioButton>
    etc...
</StackPanel>

不幸的是,由于我没有使用固定宽度的字体,TextBlock的宽度会在字体粗细改变时发生变化,整个单选按钮面板会相应地移动,这在视觉上会有些不和谐。

2 个答案:

答案 0 :(得分:3)

我通过在TextBlock的内容中添加隐藏的RadioButton并将FontStyle明确设置为Bold来为此创建了解决办法:

<RadioButton Style="{StaticResource BoldWhenChecked}">
    <Grid>
        <TextBlock Text="Item 1" />
        <TextBlock Text="Item 1" FontStyle="Bold" Visibility="Hidden" />
    </Grid>
</RadioButton>

这样,当选择RadioButton并使可见TextBlock变为粗体时,宽度不会改变,因为隐藏的TextBlock已经适当地调整了网格的大小。

答案 1 :(得分:0)

就个人而言,我会尝试更好地组织我的布局,以便它们不依赖于单选按钮的大小。也就是说,如果你绝对坚持这样做,那么你需要在Bold时根据它的大小设置每个TextBlock的宽度,并且如果你需要更改文本和/,它将导致它更新为此,您需要将Width属性绑定到接受所有其他值的Converter。

从设置文本框宽度的样式开始:

<Style TargetType="{x:Type TextBlock}">
        <Setter Property="Width">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource TextToWidthConverter}">
                    <Binding Path="Text" RelativeSource="{RelativeSource Self}" UpdateSourceTrigger="PropertyChanged"/>
                    <Binding Path="FontFamily" RelativeSource="{RelativeSource Self}" UpdateSourceTrigger="PropertyChanged"/>
                    <Binding Path="FontStyle" RelativeSource="{RelativeSource Self}" UpdateSourceTrigger="PropertyChanged"/>
                    <Binding Path="FontStretch" RelativeSource="{RelativeSource Self}" UpdateSourceTrigger="PropertyChanged"/>
                    <Binding Path="FontSize" RelativeSource="{RelativeSource Self}" UpdateSourceTrigger="PropertyChanged"/>
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>

现在添加值转换器本身的代码(请注意我使用code posted by Clarke Kent in another StackOverflow answer来测量文本):

public class TextToWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var text = values[0] as String;
        var fontFamily = values[1] as FontFamily;
        var fontStyle = (FontStyle)values[2];
        var fontStretch = (FontStretch)values[3];
        var fontSize = (Double)values[4];
        var size = MeasureText(text, fontFamily, fontStyle, FontWeights.Bold, fontStretch, fontSize);
        return size.Width;
    }

    public object[] ConvertBack(object values, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Get the required height and width of the specified text. Uses Glyph's
    /// </summary>
    public static Size MeasureText(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double fontSize)
    {
        Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
        GlyphTypeface glyphTypeface;

        if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
        {
            return MeasureTextSize(text, fontFamily, fontStyle, fontWeight, fontStretch, fontSize);
        }

        double totalWidth = 0;
        double height = 0;

        for (int n = 0; n < text.Length; n++)
        {
            ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]];

            double width = glyphTypeface.AdvanceWidths[glyphIndex] * fontSize;

            double glyphHeight = glyphTypeface.AdvanceHeights[glyphIndex] * fontSize;

            if (glyphHeight > height)
            {
                height = glyphHeight;
            }

            totalWidth += width;
        }

        return new Size(totalWidth, height);
    }

    /// <summary>
    /// Get the required height and width of the specified text. Uses FortammedText
    /// </summary>
    public static Size MeasureTextSize(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double fontSize)
    {
        FormattedText ft = new FormattedText(text,
                                             CultureInfo.CurrentCulture,
                                             FlowDirection.LeftToRight,
                                             new Typeface(fontFamily, fontStyle, fontWeight, fontStretch),
                                             fontSize,
                                             Brushes.Black);
        return new Size(ft.Width, ft.Height);
    }
}

但是,再一次,在一个真正的应用程序中,我会尝试通过将它们放入网格或其他东西来正确解决这个问题。