wpf icon indicating copy to clipboard operation
wpf copied to clipboard

Typing Japanese in a WPF RichTextBox

Open vsfeedback opened this issue 5 years ago • 5 comments

This issue has been moved from a ticket on Developer Community.


If you type a line in Japanese in a WPF RichTextBox control and then wrap it with Shift + enter and then rewrite it Will the top line and the writing be followed, is there any way to deal with this phenomenon?


Original Comments

Feedback Bot on 11/19/2019, 02:01 PM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.

PR [MSFT] on 12/10/2019, 09:19 PM:

Hi,
We would be happy to help you out. We’ll need some more information to better investigate this issue.
Can you share with us if the issue that you’re seeing only happens when you’re modifying the text in RichTextBox directly in the XAML Designer or is this something which is more of an issue with how WPF RichTextBox control renders ?

lee hanhyeong on 12/16/2019, 10:57 PM:

(private comment, text removed)

Feedback Bot on 4/1/2020, 00:06 PM:

Thank you for sharing your feedback! Our teams prioritize action on product issues with broad customer impact. See details at: https://docs.microsoft.com/en-us/visualstudio/ide/report-a-problem?view=vs-2019#faq. In case you need answers to common questions or need assisted support, be sure to use https://visualstudio.microsoft.com/vs/support/. We’ll keep you posted on any updates to this feedback.

Feedback Bot on 4/24/2020, 00:24 PM:

I have detected that for the last 35 days, this issue didn't have much product team activity and a very small amount of new votes or comments. Based on this, its severity, and affected area, it’s my experience that this issue is very unlikely to be fixed.


Original Solutions

(no solutions)

vsfeedback avatar Nov 06 '20 03:11 vsfeedback

More details on the repro steps from the initial ticket:

  1. install japanese language pack in window 10

  2. create WPF application project

  3. add RichTextBox in MainWindow.xaml

<Grid x:Name="gridMain"> <RichTextBox /> </Grid>
  1. build project

  2. change os input language to japanese

  3. write japanese in richtextbox

  4. shift + enter (next line)

  5. write japanese again..

  6. you will see that japanese come back previous line.

ryalanms avatar Nov 13 '20 20:11 ryalanms

I'm facing this problem too, is there any way to deal with this issue? I am using WPF RichTextBox with .Net Core 3.1.

toshiyuki-e-suzuki avatar Aug 29 '23 09:08 toshiyuki-e-suzuki

Hello, here is a workaround fix for this issue:

bool isLastInputShiftEnter = false;

private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
    {
        isLastInputShiftEnter = true;
    }
    else if (isLastInputShiftEnter && e.Key == Key.Enter)
    {
        e.Handled = true;
        TextPointer caretPosition = richTextBox.CaretPosition;
        caretPosition.InsertTextInRun("\u000D");
        if (caretPosition.LogicalDirection == LogicalDirection.Backward)
        {
            richTextBox.CaretPosition = caretPosition.GetPositionAtOffset(1, LogicalDirection.Forward);
        }
        isLastInputShiftEnter = false;
    }
    else
    {
        isLastInputShiftEnter = false;
    }
}

Here, we are adding "\u000D" when the user presses Shift+Enter. This is also treated as a line break but without causing the existing issue.

himgoyalmicro avatar Jul 24 '24 14:07 himgoyalmicro

@himgoyalmicro The flag does not seem right, wouldn't it trigger if you press shift, then release it and then press enter? You can use e.KeyboardDevice.Modifiers to check for the modifier.

miloush avatar Jul 24 '24 14:07 miloush

Thank you so much for pointing this out, @miloush!!

Here is the updated workaround:

private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter && e.KeyboardDevice.Modifiers == ModifierKeys.Shift)
    {
        e.Handled = true;
        TextPointer caretPosition = richTextBox.CaretPosition;
        caretPosition.InsertTextInRun("\u000D");
        if (caretPosition.LogicalDirection == LogicalDirection.Backward)
        {
            richTextBox.CaretPosition = caretPosition.GetPositionAtOffset(1, LogicalDirection.Forward);
        }
    }
}

himgoyalmicro avatar Jul 25 '24 07:07 himgoyalmicro

If you attempt to export the content of the Rich Textbox with the above workaround, the line breaks will disappear in the exported document. To address this, here is a workaround for exporting the text in rich text format with the line breaks:

private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter && e.KeyboardDevice.Modifiers == ModifierKeys.Shift)
    {
        e.Handled = true;
        TextPointer caretPosition = richTextBox.CaretPosition;
        caretPosition.InsertTextInRun("\u2028");
        if (caretPosition.LogicalDirection == LogicalDirection.Backward)
        {
            richTextBox.CaretPosition = caretPosition.GetPositionAtOffset(1, LogicalDirection.Forward);
        }
    }
}

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
    var dlg = new Microsoft.Win32.SaveFileDialog();
    dlg.FileName = "Document";
    dlg.DefaultExt = ".rtf";
    dlg.Filter = "Rich Text Format (.rtf)|*.rtf";

    var range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
    string modifiedRtfContent = string.Empty;
    using (MemoryStream memoryStream = new MemoryStream())
    {
        range.Save(memoryStream, DataFormats.Rtf);
        string rtfContent = Encoding.UTF8.GetString(memoryStream.ToArray());

        // Replace \u2028 with \line in the RTF content
        modifiedRtfContent = rtfContent.Replace(@"\u8232?", @"\line ");

    }
    if (dlg.ShowDialog() == true)
    {
        using (var fs = new FileStream(dlg.FileName, FileMode.Create))
        {
            byte[] bytes = Encoding.Default.GetBytes(modifiedRtfContent);
            fs.Write(bytes, 0, bytes.Length);
        }
    }
}

Here we are replacing the added "\u2028"(Line Separator) in the rtf to \line so that the line break is not lost when we are exporting the text: modifiedRtfContent = rtfContent.Replace(@"\u8232?", @"\line ");

Explanation for how "\u2028" is converted to "\u8232?": We encoded this RTF content in UTF format by doing this: string rtfContent = Encoding.UTF8.GetString(memoryStream.ToArray());

So encoding of Unicode character in UTF is based on this formula: x => @"\u" + (int)x + "?"

Here the ? is the fallback character. If a program understands Unicode, it will render the character corresponding to the unicode. If a program does not support Unicode, it will render the fallback character ?.

So for our case \u2028 is converted to \u8232?

Since int(2028) = 8232

And the current program does not support this Unicode it is converted to \u8232? (fallback character)

himgoyalmicro avatar Aug 20 '24 08:08 himgoyalmicro

If we import an existing rich text document into the WPF rich text box and try to insert a Japanese character after a line break, we will encounter the existing issue of character getting inserted in the previous line.

Here is a workaround that will replace all the line break to \u2028 (Line Separator) Unicode character while importing to resolve the issue:

private void importButton_Click(object sender, RoutedEventArgs e)
{
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = "RTF Files (*.rtf)|*.rtf|All Files (*.*)|*.*";

    if (openFileDialog.ShowDialog() == true)
    {
        string filePath = openFileDialog.FileName;
        string modifiedRtfContent = string.Empty;
        using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            using (StreamReader reader = new StreamReader(fileStream, Encoding.Default))
            {
                string rtfContent = reader.ReadToEnd();
                //Replace \line with \u2028 in the RTF content
                modifiedRtfContent = rtfContent.Replace(@"\line ", @"\u8232?");
            }
        }
        TextRange range = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
        using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(modifiedRtfContent)))
        {
            range.Load(memoryStream, DataFormats.Rtf);
        }
    }
}

himgoyalmicro avatar Aug 20 '24 09:08 himgoyalmicro