未设置宽度的 WPF RichTextBox

发布于 2024-07-09 19:06:23 字数 693 浏览 3 评论 0原文

我有以下 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 中创建此窗口,您可以看到,当您没有指定窗口的宽度时,它会将文本包装在单列中,一次一个字母。 我缺少什么吗? 如果这是已知的控制缺陷,是否有任何解决方法?

I have the following XAML code:

<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>

... If you create this window in XAML, you can see that when you don't specify a width for the window, it wraps the text in a single column, one letter at a time. Is there something I'm missing? If it's a known deficiency in the control, is there any workaround?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

表情可笑 2024-07-16 19:06:23

这是 WPF RichTextBox 中已确认的错误。 要修复此问题,请将 FlowDocument 的 PageWidth 绑定到 RichTextBox 宽度,即

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

编辑:
为 FlowDocument 指定一个名称,以便您可以在代码隐藏中访问它,并且永远不会在代码隐藏中新建流程文档。

This is a confirmed bug with the WPF RichTextBox. To fix it, Bind the PageWidth of the FlowDocument to the RichTextBox width, i.e.

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

EDIT:
Give the FlowDocument a name so that you can access it in the code behind and never new the flow document in codebehind.

失而复得 2024-07-16 19:06:23

尝试将 FlowDocument 的宽度(一种方式)绑定到容器 RichTextBox 的宽度。

为我工作...

Try binding the FlowDocument's width (one way) to the width of the container RichTextBox.

Worked for me...

娇妻 2024-07-16 19:06:23

本文中的方法为我工作:

WPF RichTextBox不提供调整宽度的功能
到正文。 据我所知,RichTextBox 在中使用 FlowDocumentView
它的视觉树来呈现流文档。 它将占用可用的
空间来渲染其内容,因此它不会调整其大小以适应
内容。 由于这是一个内部类,因此我们似乎无法重写
让 RichTextBox 调整其大小的布局过程
文本。

因此,我认为您的做法是正确的。
不幸的是,根据我的研究,没有直接的方法
测量 RichTextBox 中渲染文本的大小。

我们可以尝试一个解决方法。 我们可以循环遍历流程文档
在 RichTextBox 中递归地检索所有 Run 和 Paragraph 对象。
然后我们将它们转换为FormattedText以获得大小。

本文演示了如何将 FlowDocument 转换为
格式化文本。 我还使用编写了一个简单的示例
该文章中的 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();
    }
  }

The approach in this article worked for me:

WPF RichTextBox doesn't provide the functionality to adjust its width
to the text. As far as I know, RichTextBox use a FlowDocumentView in
its visual tree to render the Flowdocument. It will take the available
space to render its content, so it won't adjust its size to the
content. Since this is an internal class, it seems we cannot override
the layout process to let a RichTextBox to adjust its size to the
text.

Therefore, I think your approach is in the right direction.
Unfortunelately, based on my research, there is no straightforward way
to measure the size of the rendered text in a RichTextBox.

There is a workaround we can try. We can loop through the flowdocument
in RichTextBox recursively to retrieve all Run and Paragraph objects.
Then we convert them into FormattedText to get the size.

This article demonstrates how to convert a FlowDocument to
FormattedText. I also write a simple sample using the
FlowDocumentExtensions class in that article.

    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();
    }
  }
撑一把青伞 2024-07-16 19:06:23

我复制粘贴了您的代码,但它不在单列中,您的某个地方的宽度是否很小? 例如,可能在后面的代码中定义。

I copy pasted your code and its not in a single column, Do you have a width somewhere that is small? Maybe defined on the code behind for instance.

美男兮 2024-07-16 19:06:23

我注意到,只有当我的默认 ScrollViewer 样式显式设置 Horizo​​ntalScrollBarVisibility=Hidden 时,我才会遇到此问题。
删除此设置器(默认值是Hidden)解决了我的RichTextBox中的单列问题。

I noticed that I only had this issue when my default ScrollViewer style explicitly set HorizontalScrollBarVisibility=Hidden.
Removing this setter (default value is Hidden anyway) fixed the single column issue for me in my RichTextBox.

十级心震 2024-07-16 19:06:23

只是为了记录,因为我认为这个线程缺少一些解释,根据原因: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);
    }

Just for the record as I think this thread is missing some explanations as per the why: RichTextBox MeasureOverride implementation is like that. I won't call that a bug, maybe just a poor design behavior justified by the fact that just like mentioned above the FlowDocument is not cheap to measure due to its complexity. Bottom line, avoid unlimited Width constraint by binding MinWidth or wrap it in a limiting container.

    /// <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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文