El enfoque en this article trabajó para mí:
WPF RichTextBox no proporciona la funcionalidad para ajustar su anchura al texto. Hasta donde yo sé, RichTextBox utiliza un FlowDocumentView en su árbol visual para representar el documento de flujo. Tomará el espacio disponible para representar su contenido, por lo que no ajustará su tamaño al contenido . Como se trata de una clase interna, parece que no podemos anular el proceso de disposición para permitir que un RichTextBox ajuste su tamaño al texto .
Por lo tanto, creo que su enfoque va en la dirección correcta. Desafortunadamente, en base a mi investigación, no hay una forma directa de para medir el tamaño del texto procesado en un RichTextBox.
Hay una solución alternativa que podemos intentar. Podemos recorrer el documento de flujo en RichTextBox recursivamente para recuperar todos los objetos Ejecutar y Párrafo. Luego los convertimos en FormattedText para obtener el tamaño.
This article demuestra cómo convertir un FlowDocument a FormattedText. También escribo una muestra simple usando la clase FlowDocumentExtensions en ese artículo.
public Window2()
{
InitializeComponent();
StackPanel layoutRoot = new StackPanel();
RichTextBox myRichTextBox = new RichTextBox() { Width=20};
this.Content = layoutRoot;
layoutRoot.Children.Add(myRichTextBox);
myRichTextBox.Focus();
myRichTextBox.TextChanged += new TextChangedEventHandler((o,e)=>myRichTextBox.Width=myRichTextBox.Document.GetFormattedText().WidthIncludingTrailingWhitespace+20);
}
public static class FlowDocumentExtensions
{
private static IEnumerable<TextElement> GetRunsAndParagraphs(FlowDocument doc)
{
for (TextPointer position = doc.ContentStart;
position != null && position.CompareTo(doc.ContentEnd) <= 0;
position = position.GetNextContextPosition(LogicalDirection.Forward))
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd)
{
Run run = position.Parent as Run;
if (run != null)
{
yield return run;
}
else
{
Paragraph para = position.Parent as Paragraph;
if (para != null)
{
yield return para;
}
}
}
}
}
public static FormattedText GetFormattedText(this FlowDocument doc)
{
if (doc == null)
{
throw new ArgumentNullException("doc");
}
FormattedText output = new FormattedText(
GetText(doc),
CultureInfo.CurrentCulture,
doc.FlowDirection,
new Typeface(doc.FontFamily, doc.FontStyle, doc.FontWeight, doc.FontStretch),
doc.FontSize,
doc.Foreground);
int offset = 0;
foreach (TextElement el in GetRunsAndParagraphs(doc))
{
Run run = el as Run;
if (run != null)
{
int count = run.Text.Length;
output.SetFontFamily(run.FontFamily, offset, count);
output.SetFontStyle(run.FontStyle, offset, count);
output.SetFontWeight(run.FontWeight, offset, count);
output.SetFontSize(run.FontSize, offset, count);
output.SetForegroundBrush(run.Foreground, offset, count);
output.SetFontStretch(run.FontStretch, offset, count);
output.SetTextDecorations(run.TextDecorations, offset, count);
offset += count;
}
else
{
offset += Environment.NewLine.Length;
}
}
return output;
}
private static string GetText(FlowDocument doc)
{
StringBuilder sb = new StringBuilder();
foreach (TextElement el in GetRunsAndParagraphs(doc))
{
Run run = el as Run;
sb.Append(run == null ? Environment.NewLine : run.Text);
}
return sb.ToString();
}
}
Este problema me sigue sucediendo intermitentemente, así que acabo de derrumbar y llamé a la cuadrícula principal como "mainGrid" y establecí Width = "{Binding ElementName = mainGrid, Path = ActualWidth}" y Height = "{Binding ElementName = mainGrid, Path = ActualHeight} "para forzar el comportamiento que quiero. – Michael