WPF RichTextBox без установленной ширины - PullRequest
22 голосов
/ 08 декабря 2008

У меня есть следующий код XAML:

<Window x:Class="RichText_Wrapping.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<Grid>
    <RichTextBox Height="100" Margin="2" Name="richTextBox1">
        <FlowDocument>
            <Paragraph>
                This is a RichTextBox - if you don't specify a width, the text appears in a single column
            </Paragraph>
        </FlowDocument>
    </RichTextBox>
</Grid>

... Если вы создаете это окно в XAML, вы можете видеть, что, если вы не укажете ширину окна, оно будет заключать текст в один столбец, по одной букве за раз. Я что-то упускаю? Если это известный недостаток в контроле, есть ли обходной путь?

Ответы [ 6 ]

23 голосов
/ 14 апреля 2010

Это подтвержденная ошибка в WPF RichTextBox. Чтобы исправить это, привяжите PageWidth FlowDocument к ширине RichTextBox, т.е.

<RichTextBox Name="rtb">
    <FlowDocument Name="rtbFlowDoc" PageWidth="{Binding ElementName=rtb, Path=ActualWidth}" />
</RichTextBox>

EDIT: Дайте FlowDocument имя, чтобы вы могли получить к нему доступ в коде и никогда не создавать новый документ потока в codebehind.

8 голосов
/ 03 марта 2009

Попробуйте привязать ширину FlowDocument (в одну сторону) к ширине контейнера RichTextBox.

работал для меня ...

6 голосов
/ 09 февраля 2012

Подход в этой статье у меня работал:

WPF RichTextBox не обеспечивает функциональность для регулировки его ширины к тексту. Насколько я знаю, RichTextBox использует FlowDocumentView в его визуальное дерево для визуализации Flowdocument. Это займет доступное пространство для отображения его содержимого, поэтому он не будет регулировать его размер содержание. Поскольку это внутренний класс, кажется, мы не можем переопределить процесс макета, чтобы RichTextBox мог регулировать свой размер в соответствии с текст.

Поэтому я думаю, что ваш подход в правильном направлении. К сожалению, исходя из моих исследований, нет прямого пути измерить размер отображаемого текста в RichTextBox.

Есть обходной путь, который мы можем попробовать. Мы можем перебрать поток документов в RichTextBox рекурсивно для извлечения всех объектов Run и Paragraph. Затем мы конвертируем их в FormattedText, чтобы получить размер.

В этой статье показано, как преобразовать FlowDocument в FormattedText. Я также пишу простой пример, используя Класс FlowDocumentExtensions в этой статье.

    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();
    }
  }
2 голосов
/ 09 декабря 2008

Я скопировал и вставил ваш код, а его нет в одном столбце. У вас есть где-нибудь маленькая ширина? Может быть определен в коде позади, например.

1 голос
/ 14 февраля 2017

Только для записи, так как я думаю, что в этой теме отсутствуют некоторые объяснения в соответствии с , почему : реализация RichTextBox MeasureOverride такая. Я не буду называть это ошибкой, может быть, просто плохим поведением при проектировании, оправданным тем, что, как уже упоминалось выше, FlowDocument не дешев из-за его сложности. Итог: избегайте неограниченного ограничения ширины, связывая MinWidth или оборачивая его в ограничивающий контейнер.

    /// <summary>
    /// Measurement override. Implement your size-to-content logic here.
    /// </summary>
    /// <param name="constraint">
    /// Sizing constraint.
    /// </param>
    protected override Size MeasureOverride(Size constraint)
    {
        if (constraint.Width == Double.PositiveInfinity)
        {
            // If we're sized to infinity, we won't behave the same way TextBox does under
            // the same conditions.  So, we fake it.
            constraint.Width = this.MinWidth;
        }
        return base.MeasureOverride(constraint);
    }
1 голос
/ 25 марта 2014

Я заметил, что у меня была эта проблема, только когда мой стиль по умолчанию ScrollViewer явно устанавливал HorizontalScrollBarVisibility=Hidden.
Удаление этого установщика (значение по умолчанию Hidden в любом случае) исправило проблему с одним столбцом для меня в моем RichTextBox.

...