5

Is there a way in WPF to get the text formatted as it display on the textbox when TextWrapping="Wrap"?

<TextBox   Width="200"
           TextWrapping="Wrap"                 
           VerticalScrollBarVisibility="Auto"
           HorizontalScrollBarVisibility="Auto"  />

I've tried to use TextFormatter class, but it onty allow me to draw the text to a drawing context where i only need the text with line break included.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Fbeauche
  • 53
  • 1
  • 4
  • i am sorry but couldn't understand the problem statement. Is it that you want to copy the text from that textbox and while pasting somewhere else would like to preserve the wrapped positions? – publicgk Apr 19 '11 at 18:35
  • As text or as a visual/image? – Danny Varod Apr 19 '11 at 18:45
  • @publicgk, my exact case is to pass the text to active report while preserving the wrapped position so i got the same wrapping than shown on screen. So i need it as Text. – Fbeauche Apr 19 '11 at 18:54

4 Answers4

3

Here's how to get the complete text with apparent line breaks.

Note:

  • Include the following classes from Advanced Text Formatting Example in your project:
    • CustomTextSource
    • FontRendering
    • GenericTextProperties
  • There are some limitations which are mentioned in CustomTextSource class. However, I believe your requirements aren't impacted by those limitations.
  • These are just examples. You may want to modify code as per your needs.
  • The code still uses a hack (although a decent one) - InputTextBox.ViewportWidth. You may want to test if the final output is exactly as desired.

See: Advanced Text Formatting and Advanced Text Formatting Example

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

Codebehind:

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;
}
publicgk
  • 3,170
  • 1
  • 26
  • 45
  • Woa , thanks a lot works perferct :). I had to adjust a bit the code since it was truncating the last char of each line except for the last one. – Fbeauche Apr 21 '11 at 16:12
  • The links to the "Advanced Text Formatting Example" are broken. – Victor Nov 19 '16 at 12:44
2

See the answer by Ian Griffiths to this question: Get Displayed Text from TextBlock

It gets the displayed text (as it is presented on the screen) from a TextBlock but I think you should be able to use it for a TextBox as well

Community
  • 1
  • 1
Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
  • Good post there, but i dont seem to get it working well with a textbox. I was able to get the displayed text with some tweak, but i can't get the whole text in the textbox... – Fbeauche Apr 20 '11 at 14:09
1

For that you have to write your own logic by making use of text measurement API.

STEP 1: Bresk the textbox text in to words.

STEP 2: Then measure each word width and combine them until the line width is less than textbox width.

Refer this post which explains about text measurement process. (social.msdn.microsoft.com/forums/en-US/wpf/thread/…)

Karthik Mahalingam
  • 1,071
  • 8
  • 10
1

If all you want is the text of textbox (complete text and not just the visible part), to be displayed as text (with apparent line breaks) on the same window in some textblock, a quick hack could be:

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;

If its required in some other place, you can carry the values to that place and use them on the textblock there.

If you need the complete text (with apparent line breaks) as a list of string (e.g. List<string>) where each item represents the apparent line, you will need a complex solution.
Also, if you need only the visible part of text as displayed in the textbox, again some complex solution is required.

publicgk
  • 3,170
  • 1
  • 26
  • 45