首页 > 代码库 > WPF中RichTextBox高度自适应问题解决方法

WPF中RichTextBox高度自适应问题解决方法

最近做一个项目需要用到RichTextBox来显示字符串,但是不允许出现滚动条,在RichTextBox宽度给定的条件下,RichTextBox的高度必须正好显示内容,而不出现下拉滚动条。

这样就要计算要显示的文本的高度,在网上找了许久,其中使用了FormattedText类来计算文本的高度,发现FormattedText计算出的高度总是比RichTextBox需要的高度小。

在网上找到,可自定义一个控件,继承System.Windows.Controls.RichTextBox。

private void AdjustHeight() 
         { 
                 Rect rectStart = Document.ContentStart.GetCharacterRect(LogicalDirection.Forward); 
                 Rect rectEnd = Document.ContentEnd.GetCharacterRect(LogicalDirection.Forward); 
                 var height = rectEnd.Bottom - rectStart.Top; 
                 var remainH = rectEnd.Height / 2.0; 
                 var myHeight = Math.Min(MaxHeight, Math.Max(MinHeight, height + remainH)); 
                 this.Height = myHeight;

          }

        来计算Document的高度,但是在rectStart ,rectEnd 得到的值总是为Empty,没有办法来计算高度。后来发现只有在RichTextBox的IsArrangeValid值为True时,rectStart 、rectEnd 值才是有效的,必须放在

protected override void OnRender(DrawingContext drawingContext) 
           { 
                   base.OnRender(drawingContext); 
                   AdjustHeight();

           }

        这样才是有效的,但是包含这个自定义的RichTextBox的母控件必须是自定义的,按照如下重载MeasureOverride,ArrangeOverride方法,母控件对子控件进行二次测量、规划位置。重新对自定义的RichTextBox进行计算高度。

protected override Size MeasureOverride(Size availableSize) 
            { 
                    Size panelDesiredSize = new Size();

                    foreach (UIElement child in InternalChildren) 
                    { 
                            child.Measure(availableSize); 
                            panelDesiredSize = child.DesiredSize; 
                    }

                    return panelDesiredSize; 
            } 
            protected override Size ArrangeOverride(Size finalSize) 
            { 
                    foreach (UIElement child in InternalChildren) 
                    { 
                            double x = 10; 
                            double y = 5;

                            child.Arrange(new Rect(new Point(x, y), child.DesiredSize)); 
                    } 
                    return finalSize; // Returns the final Arranged size 
            }

这样实现的效果发现,UI运行比较慢。

后发现可以使用TextLine类来计算流文档的高度,关键代码如下:

public void Calculate() 
              {

                      var currentRendering = new FontRendering( 
    document.FontSize, 
    document.TextAlignment, 
    null, 
    document.Background, 
      new Typeface(document.FontFamily, document.FontStyle, document.FontWeight, document.FontStretch));


                      var textStore = new CustomTextSource(); 
                      textStore.Text = Content; 
                      textStore.FontRendering = currentRendering; 
                      var TextParagraphProperties = new GenericTextParagraphProperties(currentRendering);

                      System.Windows.Media.TextFormatting.TextFormatter 
          formatter = System.Windows.Media.TextFormatting.TextFormatter.Create(); 
                      TextLine myTextLine = null; 
                      int startPoint = 0; 
                      int RowCont = 0; 
                      do 
                      { 
                              myTextLine = formatter.FormatLine( 
          textStore, startPoint, document.MinPageWidth, TextParagraphProperties, null); 
                              //myTextLine.Draw(dc, new Point(0, RowCont * document.LineHeight), InvertAxes.None); 
                              startPoint = startPoint + myTextLine.Length; 
                              RowCont++; 
                      } while (startPoint < Content.Length); 
                      this.Height = Math.Max(RowCont * document.LineHeight, miniHight); 
              }

这个方法,可以在任何地方被正确的执行。一般可以在RichTextBox自定义控件的构造函数中调用,设定RichTextBox的高度。

关于TextLine 的使用,可以参考http://www.cnblogs.com/Clingingboy/archive/2010/12/03/1895326.html

最后RichTextBox实现的效果相当的好: