2013-01-16 49 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該死的你是對的..我會檢查出來 –