2013-01-16 45 views
4

我有一个TextBlock具有包装文本的固定大小。有时短暂有时很长。用于TextBlock的动态字体大小与包装

如果文本越来越长它不是完全显示这样

enter image description here

我怎样才能让字体大小的灵活性,以使文本适合静态大小的文本框?

+0

你可以尝试使用[视框(http://msdn.microsoft.com/ en-us/library/system.windows.controls.viewbox.aspx),但您可能会遇到ViewBox中包装的问题。 –

+0

是啊,你的猜测似乎是正确的,它杀死了包装。感谢无论如何,我没有偶然发现那个元素! – Ostkontentitan

+0

您是否打开JavaScript解决方案? – ic3b3rg

回答

10

我的解决方案如下:

设置字体大小的值,比你不想任何大。 当您更改字体大小或更改内容时,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()。

+0

非常感谢,这帮助我! – Ostkontentitan

+0

谢谢,这对我有帮助。注意;我意识到这不适用于OP的情况,但在Windows 10应用程序中,您可以在桌面上的窗口中调整大小,这将导致文本缩小但不会再变大。 – tagy22

+0

这太棒了! – xleon

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); 
      } 
     } 
    } 
+1

'_typeface'不在您的示例中使用。 – canton7

+0

@ canton7该死的你是对的..我会检查出来 –