WPF:从文本框中获取“换行”文本

5
在WPF中,当TextWrapping="Wrap"时,有没有一种方法可以获取文本在文本框上显示的格式?
<TextBox   Width="200"
           TextWrapping="Wrap"                 
           VerticalScrollBarVisibility="Auto"
           HorizontalScrollBarVisibility="Auto"  />

我尝试使用TextFormatter类,但它只允许我将文本绘制到绘图上下文中,而我只需要包含换行的文本。


很抱歉,我无法理解问题陈述。您是想从文本框中复制文本,在粘贴到其他地方时保留换行位置吗? - publicgk
作为文字。 - Danny Varod
@publicgk,我的确切情况是将文本传递给活动报告,同时保留换行位置,以便我能够获得与屏幕上显示的相同的换行效果。所以我需要它作为文本。 - Fbeauche
4个回答

3

以下是如何获取具有明显换行符的完整文本。

注意:

  • 在您的项目中包含高级文本格式示例中的以下类:
    • CustomTextSource
    • FontRendering
    • GenericTextProperties
  • CustomTextSource类中提到了一些限制。然而,我相信这些限制不会影响您的要求。
  • 这些只是示例。您可能需要根据自己的需求修改代码。
  • 该代码仍使用一个技巧(尽管是不错的技巧)- InputTextBox.ViewportWidth。您可能需要测试最终输出是否与所需完全一致。

请参见:高级文本格式高级文本格式示例

示例代码
XAML:

<Window x:Class="TextFormatterForWrappedText.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox Width="200"
            x:Name="InputTextBox"
            TextWrapping="Wrap"
            VerticalScrollBarVisibility="Auto"
            HorizontalScrollBarVisibility="Auto" Margin="23,12,280,241" />
        <TextBox x:Name="FormattedDisplayTextBox" Height="172"
                 HorizontalAlignment="Left" VerticalAlignment="Top"
                 Margin="23,105,0,0" Width="438" AcceptsReturn="True"
                 TextWrapping="Wrap" />
        <Button HorizontalAlignment="Left" VerticalAlignment="Top"
                Margin="257,12,0,0" Height="23" Content="Copy"
                Name="CopyButton" Width="129" Click="CopyButton_Click" />
    </Grid>
</Window>

代码后置文件:

private void CopyButton_Click(object sender, RoutedEventArgs e)
{
    List<string> stringList = GetTextAsStringList();
    StringBuilder sb = new StringBuilder();
    foreach (string s in stringList)
    {
        sb.Append(s);
        sb.Append("\r\n");
    }

    Clipboard.SetData(System.Windows.DataFormats.Text, sb.ToString());

    FormattedDisplayTextBox.Clear();
    FormattedDisplayTextBox.Text = sb.ToString();
}

private List<string> GetTextAsStringList()
{
    List<string> stringList = new List<string>();
    int pos = 0;
    string inputText = InputTextBox.Text;

    CustomTextSource store = new CustomTextSource();
    store.Text = inputText;
    store.FontRendering = new FontRendering(InputTextBox.FontSize,
                                            InputTextBox.TextAlignment,
                                            null,
                                            InputTextBox.Foreground,
                                            new Typeface(InputTextBox.FontFamily,
                                                InputTextBox.FontStyle,
                                                InputTextBox.FontWeight,
                                                InputTextBox.FontStretch));

    using (TextFormatter formatter = TextFormatter.Create())
    {
        while (pos < store.Text.Length)
        {
            using (TextLine line = formatter.FormatLine(store,
                                    pos,
                                    InputTextBox.ViewportWidth,
                                    new GenericTextParagraphProperties(
                                        store.FontRendering),
                                    null))
            {
                stringList.Add(inputText.Substring(pos, line.Length - 1));
                pos += line.Length;
            }
        }
    }

    return stringList;
}

非常感谢,非常完美:)。由于代码截断了每行的最后一个字符,除了最后一行,所以我不得不稍微调整一下代码。 - Fbeauche
“高级文本格式示例”的链接已损坏。” - Victor

2

请查看Ian Griffiths在此问题上的回答:获取TextBlock中的显示文本

该方法可以从中获取显示的文本(即屏幕上呈现的文本),但我认为您也应该能够将其用于。


很好的帖子,但是我似乎无法在文本框中正常工作。我能够通过一些调整获得显示的文本,但我无法获取文本框中的全部文本... - Fbeauche

1
如果您只想要文本框的文本(完整的文本而不仅仅是可见部分)以文本形式(带有明显的换行符)显示在同一窗口中的某个文本块中,一个快速的技巧可能是:
FormattedText ft = new FormattedText(textBox1.Text,
    System.Globalization.CultureInfo.CurrentCulture,
    textBox1.FlowDirection,
    new Typeface(textBox1.FontFamily,
        textBox1.FontStyle,
        textBox1.FontWeight,
        textBox1.FontStretch),
    textBox1.FontSize,
    textBox1.Foreground);
ft.TextAlignment = textBox1.TextAlignment;
ft.Trimming = TextTrimming.None;

ft.MaxTextWidth = textBox1.ViewportWidth;

textBlock1.Width = textBox1.ViewportWidth;
textBlock1.Height = ft.Height;

textBlock1.TextAlignment = textBox1.TextAlignment;
textBlock1.TextWrapping = textBox1.TextWrapping;
textBlock1.Text = textBox1.Text;

如果在其他地方需要,您可以将这些值传递到那个地方,并在文本块中使用它们。

如果您需要完整的文本(带有明显的换行符)作为字符串列表(例如List<string>),其中每个项目表示明显的行,则需要一个复杂的解决方案。
此外,如果您只需要文本框中显示的可见部分,同样需要一些复杂的解决方案。


我需要完整的文本,而且我不打算在屏幕上显示它 :( - Fbeauche

1
为此,您必须利用文本测量 API 编写自己的逻辑。 步骤 1:将文本框文本拆分为单词。 步骤 2:然后测量每个单词的宽度并组合它们,直到行宽小于文本框宽度。
请参阅此帖子,其中介绍了文本测量过程。(social.msdn.microsoft.com/forums/en-US/wpf/thread/…)

这不是重点,他/她想要以TextBlock自动强制执行的格式获取文本。 - H.B.
@H.B. 对不起!我误解了他的意思,我以为他在寻找一种不使用TextBox来处理溢出文本的方法。 - Karthik Mahalingam
顺便问一下,将文本框设置为只读是否是一个有效的选项? - Karthik Mahalingam
不行,我需要用户输入文本。 - Fbeauche
谢谢,我刚刚修改了我的答案。稍后会发布代码片段。 - Karthik Mahalingam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接