我会跳到追逐:有没有办法告诉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
的宽度会在字体粗细改变时发生变化,整个单选按钮面板会相应地移动,这在视觉上会有些不和谐。
答案 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);
}
}
但是,再一次,在一个真正的应用程序中,我会尝试通过将它们放入网格或其他东西来正确解决这个问题。