4

我有一个固定大小的 TextBlock,它是环绕文本的。有时短有时长。

如果文本变得很长,则不会完全像这样显示

在此处输入图像描述

如何使 Fontsize 灵活以使文本适合具有静态大小的 TextBox?

4

2 回答 2

11

我的解决方案如下:

将 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 并不重要,这样我就不会担心“不走运”的文本,这将花费太长时间来渲染。但我认为 Math.Floor() 如果你不想有一个非常高的文本框(比如 2000 像素),可以省略很多文本。

于 2013-01-18T13:52:13.730 回答
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);
            }
        }
    }
于 2013-10-15T09:08:25.440 回答