我有一个TextBlock,其大小固定,包含文本。有时短有时长。
如果文字越来越长,它就不会像这样显示
如何让Fontsize灵活使文本适合静态大小的TextBox?
答案 0 :(得分:10)
我的解决方案如下:
将fontsize设置为一个值,而不是你想要的更大的值。 更改字体大小或更改内容时,TextBlock的ActualHeight会更改。我基于此构建了解决方案。 您应该为SizeChanged事件创建一个事件处理程序,并将以下代码写入其中。
private void MyTextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
double desiredHeight = 80; // Here you'll write the height you want the text to use
if (this.MyTextBlock.ActualHeight > desiredHeight)
{
// You want to know, how many times bigger the actual height is, than what you want to have.
// The reason for Math.Sqrt() is explained below in the text.
double fontsizeMultiplier = Math.Sqrt(desiredHeight / this.MyTextBlock.ActualHeight);
// Math.Floor() can be omitted in the next line if you don't want a very tall and narrow TextBox.
this.MyTextBlock.FontSize = Math.Floor(this.MyTextBlock.FontSize * fontsizeMultiplier);
}
this.MyTextBlock.Height = desiredHeight; // ActualHeight will be changed if the text is too big, after the text was resized, but in the end you want the box to be as big as the desiredHeight.
}
我使用Math.Sqrt()的原因是如果你将字体大小设置为之前的一半大,那么字体将使用的区域将是大小的四分之一,然后是之前(因为它变得像以前一样宽,一半高。你显然希望保持TextBox的宽度,只改变它的高度。
如果幸运的话,在执行此方法一次后,字体大小将是合适的。但是,根据在字体大小更改后重新包装的文本,您可能会如此“不幸”,文本将比您希望的长一行。 幸运的是,事件处理程序将再次被调用(因为您更改了字体大小),如果它仍然太大,将再次调整大小。
我试过了,它很快,结果看起来不错。 但是,我可以想象,在一个非常不幸的文本和高度选择中,在几次迭代后会达到正确的字体大小。这就是我使用Math.Floor()的原因。总而言之,如果字体大小在12.34或12的末尾并不重要,这样我就不会担心“不幸”的问题。文本,渲染时间太长。 但是我认为如果你不想拥有一个包含大量文本的高文本框(如2000像素),可以省略Math.Floor()。
答案 1 :(得分:0)
这是一个完整的解决方案,包括设置maxheight / maxwidth的选项,并且直接在渲染时计算:
public class TextBlockAutoShrink : TextBlock
{
private double _defaultMargin = 6;
private Typeface _typeface;
static TextBlockAutoShrink()
{
TextBlock.TextProperty.OverrideMetadata(typeof(TextBlockAutoShrink), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextPropertyChanged)));
}
public TextBlockAutoShrink() : base()
{
_typeface = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch, this.FontFamily);
base.DataContextChanged += new DependencyPropertyChangedEventHandler(TextBlockAutoShrink_DataContextChanged);
}
private static void TextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var t = sender as TextBlockAutoShrink;
if (t != null)
{
t.FitSize();
}
}
void TextBlockAutoShrink_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
FitSize();
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
FitSize();
base.OnRenderSizeChanged(sizeInfo);
}
private void FitSize()
{
FrameworkElement parent = this.Parent as FrameworkElement;
if (parent != null)
{
var targetWidthSize = this.FontSize;
var targetHeightSize = this.FontSize;
var maxWidth = double.IsInfinity(this.MaxWidth) ? parent.ActualWidth : this.MaxWidth;
var maxHeight = double.IsInfinity(this.MaxHeight) ? parent.ActualHeight : this.MaxHeight;
if (this.ActualWidth > maxWidth)
{
targetWidthSize = (double)(this.FontSize * (maxWidth / (this.ActualWidth + _defaultMargin)));
}
if (this.ActualHeight > maxHeight)
{
var ratio = maxHeight / (this.ActualHeight);
// Normalize due to Height miscalculation. We do it step by step repeatedly until the requested height is reached. Once the fontsize is changed, this event is re-raised
// And the ActualHeight is lowered a bit more until it doesnt enter the enclosing If block.
ratio = (1 - ratio > 0.04) ? Math.Sqrt(ratio) : ratio;
targetHeightSize = (double)(this.FontSize * ratio);
}
this.FontSize = Math.Min(targetWidthSize, targetHeightSize);
}
}
}