C#: Paste RTF in RichTextBox but keep coloring and

2020-04-16 18:23发布

Is it possible to paste text into a Rich Text Box, while keeping the font being used in the Rich Text Box for the pasted content ?

In other words, I'd like to copy something from Word that is formated (i.e: a text that uses a font X and is underlined and in blue), and then paste it in my RichTextBox.

I would like the pasted content to have the same font as that of my RichTextBox but keep its original coloring and underlining.

Is such a thing possible ?

I use winforms.

Thanks

5条回答
叛逆
2楼-- · 2020-04-16 18:34

I've tried to copy text from a word document and pasted it to a RichTextBox in runtime. Everything works fine. I did not adjust anything specific. Just dropped the RichTextBox onto a form and copied the formatted text from the MS Word document.

查看更多
冷血范
3楼-- · 2020-04-16 18:40

Old I know; Daniel's answer works for me, but only if I replace any instance of richTextBox1.Selection and simply make references to the font and size of the entire richTextBox1. In this case, any RTF I paste will inherit the fontfamily and fontsize currently being used by richTextBox1, while preserving and RTF styling.

public void SpecialPaste()
{
    var helperRichTextBox = new RichTextBox();
    helperRichTextBox.Paste();
    helperRichTextBox.SelectionStart = 0;
    helperRichTextBox.SelectionLength = 1;

Font lastFont = helperRichTextBox.SelectionFont;
int lastFontChange = 0;
for (int i = 0; i < helperRichTextBox.TextLength; ++i)
{
    helperRichTextBox.SelectionStart = i;
    helperRichTextBox.SelectionLength = 1;
    if (!helperRichTextBox.SelectionFont.Equals(lastFont))
    {
        lastFont = helperRichTextBox.SelectionFont;
        helperRichTextBox.SelectionStart = lastFontChange;
        helperRichTextBox.SelectionLength = i - lastFontChange;
        helperRichTextBox.SelectionFont = new Font(richTextBox1.Font.FontFamily, richTextBox1.Font.Size, helperRichTextBox.SelectionFont.Style);
        lastFontChange = i;
    }
}
helperRichTextBox.SelectionStart = helperRichTextBox.TextLength-1;
helperRichTextBox.SelectionLength = 1;
helperRichTextBox.SelectionFont = new Font(richTextBox1.Font.FontFamily, richTextBox1.Font.Size, helperRichTextBox.SelectionFont.Style);

richTextBox1.Rtf = helperRichTextBox.Rtf;

}

查看更多
做自己的国王
4楼-- · 2020-04-16 18:47

I know this is a bit late, but I ran into the same problem and here is my solution (hopefully this will help others):

First, handle the KeyDown event for the RichTextBox:

this.richTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.RichTextBoxKeyDown);

Next, check for paste key event and re-set the clipboard text (this is where the magic happens):

     private void RichTextBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.V)
            {
                try
                {
                    Clipboard.SetText(Clipboard.GetText());
                }
                catch (Exception)
                {
                }
            }
        }

Explanation: I'll start by saying that this was only tested with .NET 4.0. Assuming that none of the functions being used were altered, this will also work with older versions of .NET.

Calling Clipboard.GetText() returns the content in a plain text format (excluding RTF tags). Then we alter the text that's going to be pasted by calling Clipboard.SetText() with the plain text we fetched from Clipboard.GetText(). Now, when the event is done and is passed to the control, it will perform the paste fetching the latest text from the clipboard (our altered version). The reason it is wrapped in a try/catch block is because SetText sometimes throws an exception even though it successfully copied the text to the clipboard. You can of course use the other methods provided by Clipboard to get/set the text, this is just a basic version of the solution.

The newly pasted text will inherit the format of the cursor position, similar to manually typing into the RTB.

Unfortunately this will remove the style of the text as well (bold, coloring, etc)

Hope this helps!

查看更多
我欲成王,谁敢阻挡
5楼-- · 2020-04-16 18:49

Clearly this won't work the way you want it if the RTF on the clipboard contains a fragment with a /font directive. Which is very likely. Filtering the RTF fragment is only practical by pasting into a helper RichTextBox. Use the SelectionFont property then copy it back to the clipboard and Paste(). Or do it directly:

        int oldpos = richTextBox1.SelectionStart;
        richTextBox1.SelectionLength = 0;
        richTextBox1.Paste();
        int newpos = richTextBox1.SelectionStart;
        richTextBox1.SelectionStart = oldpos;
        richTextBox1.SelectionLength = newpos - oldpos;
        richTextBox1.SelectionFont = richTextBox1.Font;
        richTextBox1.SelectionStart = newpos;
查看更多
迷人小祖宗
6楼-- · 2020-04-16 18:56

This is not possible out of the box. But you can do something like this:

public void SpecialPaste()
{
    var helperRichTextBox = new RichTextBox();
    helperRichTextBox.Paste();
    for(int i=0;i<helperRichTextBox.TextLength;++i)
    {
        helperRichTextBox.SelectionStart = i;
        helperRichTextBox.SelectionLength = 1;
        helperRichTextBox.SelectionFont = new Font(richTextBox1.SelectionFont.FontFamily, richTextBox1.SelectionFont.Size,helperRichTextBox.SelectionFont.Style);
    }

    richTextBox1.SelectedRtf = helperRichTextBox.Rtf;
}

This changes the font of the pasted RTF to that of the character preceding the caret position at the time of the paste.
I assume that will get problematic pretty fast, if the text you paste is large(er). Additionally, this can be optimized in a way, that it sets the font only once for all characters in a row with the same base font as Hans suggests.

Update:
Here is the optimized version, that sets the font for a connected set of characters with the same original font:

public void SpecialPaste()
{
    var helperRichTextBox = new RichTextBox();
    helperRichTextBox.Paste();
    helperRichTextBox.SelectionStart = 0;
    helperRichTextBox.SelectionLength = 1;

    Font lastFont = helperRichTextBox.SelectionFont;
    int lastFontChange = 0;
    for (int i = 0; i < helperRichTextBox.TextLength; ++i)
    {
        helperRichTextBox.SelectionStart = i;
        helperRichTextBox.SelectionLength = 1;
        if (!helperRichTextBox.SelectionFont.Equals(lastFont))
        {
            lastFont = helperRichTextBox.SelectionFont;
            helperRichTextBox.SelectionStart = lastFontChange;
            helperRichTextBox.SelectionLength = i - lastFontChange;
            helperRichTextBox.SelectionFont = new Font(richTextBox1.SelectionFont.FontFamily, richTextBox1.SelectionFont.Size, helperRichTextBox.SelectionFont.Style);
            lastFontChange = i;
        }
    }
    helperRichTextBox.SelectionStart = helperRichTextBox.TextLength-1;
    helperRichTextBox.SelectionLength = 1;
    helperRichTextBox.SelectionFont = new Font(richTextBox1.Font.FontFamily, richTextBox1.Font.Size, helperRichTextBox.SelectionFont.Style);

    richTextBox1.SelectedRtf = helperRichTextBox.Rtf;
}

It's pretty ugly code and I am sure it can be improved and cleaned. But it does what it should.

查看更多
登录 后发表回答