首页 > 代码库 > 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实现的效果相当的好: