Detecting If Paste Event Occurred Inside a Rich Text Box

Detecting if paste event occurred inside a rich text box

It's a little bit tricky to detect a paste operation in the RichTextBox.

First solution may be to detect the WM_PASTE message overriding the WndProc but unfortunately the control doesn't send that message to itself when it performs a paste operation.

Naïve detection

To detect the keyboard events may work (you have to override the OnKeyDown function) then check if the key combinations (CTRL+V and SHIFT+INS). Something like this:

protected override OnKeyDown(KeyEventArgs e)
{
bool ctrlV = e.Modifiers == Keys.Control && e.KeyCode == Keys.V;
bool shiftIns = e.Modifiers == Keys.Shift && e.KeyCode == Keys.Insert;

if (ctrlV || shiftIns)
DoSomething();
}

It works well but you can't catch the paste operation made using the mouse (right click to open the context menu) and the paste operations made via drag & drop. If you do not need them you can use this solution (at least it's simply and straightforward).

Better detection

Assumption: when user types inside the RichTextBox he inserts one character per time. How can you use this? Well, when you detect a bigger change you detected a paste operation because user can't type more than once character per time (ok, you can argue that it's not always true because of Unicode surrogates). See also VB.NET version and more details about Unicode stuff.

private int _previousLength = 0;

private void richTextBox_TextChanged(object sender, EventArgs e)
{
int currentLength = richTextBox.Text.Length;
if (Math.Abs(currentLength - _previousLength) > 1)
ProcessAllLines();

_previousLength = currentLength;
}

Please note that you can't (because of how different IMEs work) use OnKeyDown (or similar). This works well only for western languages but it has problems with Unicode stuff (because, for example, String.Length property may be increased by two Char when user typed a single character. See also this post for much more details about this (well it's a strongly suggested reading even, even if - in this case - you don't care about it). In that post you'll also find code for a better algorithm to determine string length. In short you have to replace:

   int currentLength = richTextBox.Text.Length;

With this:

   int currentLength = StringInfo.GetTextElementEnumerator(richTextBox.Text)
.Cast<string>()
.Count();

After all this effort you may realize that...user can even paste a single character and it may go undetected. You're right, that's why this is a better detection instead of a perfect solution.

Perfect solution

The perfect solution (if you're running on Windows 8) of course exists, the native rich edit control sends an EN_CLIPFORMAT notification message. It's intended to notify a rich edit control's parent window that a paste occurred with a particular clipboard format. You can then override the WndProc of its parent to detect the WM_NOTIFY message for this notification. Anyway it's not few lines of code, check this MSDN article for details.

Detecting a paste into a RichTextBox

Because not all people may use Ctrl+V and because there are other ways to get text into a text box (such as drag and drop), I went a different route, which I will share here in case anyone else is looking for a solution.

What I did was create a field in my class:

int _lastPosition = 0;

and in the TextChanged() event I added the following:

if (SelectionStart - _lastPosition > 2)
{
// Text was pasted into text box
}
_lastPosition = SelectionStart;

I went under the assumption that if more then 2 characters were entered into the text box at a time, then text must have been pasted, because how else can someone input more then 2 characters at a time? So anyway, this worked for me. Thanks to everyone who tried to help.

How can i check a value is pasted in Textbox?

As for as I understand you said that you have already use TextBox Keypress event and now you want to check if a value is pasted in TextBox or not

If you are pasting your value thorough mouse than may be this will work fine

Private Sub TextBox_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox.MouseDown
If e.Button = Windows.Forms.MouseButtons.Right Then
//Code here what you want to do
End If
End Sub

Note this will help you if you are pasting your value through mouse right click

How to detect multiline paste in RichTextBox

Naïve detection

First solution you may think about is to detect the WM_PASTE message overriding the WndProc but unfortunately the control doesn't send that message to itself when it performs a paste operation.

Detecting keyboard events (you have to override the OnKeyDown function) and checking if the key combinations (CTRL+V and SHIFT+INS) is the one to paste text you may solve this.

Protected Sub OnKeyDown(ByVal e As KeyEventArgs)
Dim ctrlV As Boolean = e.Modifiers = Keys.Control && e.KeyCode = Keys.V
Dim shiftIns As Boolean = e.Modifiers = Keys.Shift && e.KeyCode = Keys.Insert

If ctrlV Or shiftIns Then
ProcessAllLines
End If
End Sub

It works well but you can't catch the paste operation made using the mouse (right click to open the context menu) and the paste operations made via drag & drop. If you do not need them you can use this solution (at least it's simply and straightforward).

Better detection

Assumption: when user types inside the RichTextBox he inserts one character per time. How can you use this? Well, when you detect a bigger change you detected a paste operation because user can't type more than once character per time (this isn't always true because of Unicode surrogates but it's not a problem in this case).

It doesn't work well with every IME (I didn't try with far east languages, for example) and with Unicode surrogates but for western languages it's OK (anyway even when it doesn't work you'll simply reprocess all lines). Also read this post and this post for more details about Unicode and this (twin) answer for C# version.

Dim _previousLength As Int32 = 0

Protected Sub richTextBox_TextChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim currentLength As Int32 = richTextBox.Text.Length
If Math.Abs(currentLength - _previousLength) > 1 Then
ProcessAllLines
End If

_previousLength = currentLength
End Sub

Perfect solution

The perfect solution of course exists (on Windows 8 or higher), the native rich edit control sends a EN_CLIPFORMAT notification message. It's intended to notify a rich edit control's parent window that a paste occurred with a particular clipboard format. You can then override the WndProc of its parent to detect the WM_NOTIFY message for this notification. Anyway it's not few lines of code, check this link on MSDN for details: http://msdn.microsoft.com/en-us/library/windows/desktop/hh768385(v=vs.85).aspx.

WPF handling text, image and file pasting event

You could handle the ApplicationCommands.Paste command something like this to get the pasted in text, file(s) or image:

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (e.Command == ApplicationCommands.Paste)
{
var files = Clipboard.GetFileDropList();
var text = Clipboard.GetData(DataFormats.Text);
var image = Clipboard.GetImage();
e.Handled = true;
}
}

JQuery - Paste event, stripping rich text

You could achieve something like this without needing a textarea, just processing the code in the content editable div every time that there is a change in its value, and removing all the tags but the paragraphs and line breaks.

The idea would be that every time that the content changes in the div (listen to the input event):

  • Replace in the inner HTML all </p> and <br> for non-HTML tokens (e.g.: [p] and [br] respectively).
  • Remove all HTML tags (you can do it with .text())
  • Replace the tokens that you used for their equivalents (and their openings!)
  • Wrap everything between <p> and </p>.

Here a simple demo:

$("#editable").on("input", function() {
$this = $(this);
// replace all br and closing p tags with special tokens $this.html($this.html().replace(/\<\/p\>/g,"[p]").replace(/\<br\>/g,"[br]"));
// remove all the tags, and then replace the tokens for their original values $this.html("<p>" + $this.text().replace(/\[p\]/g, "</p><p>").replace(/\[br\]/g,"<br>") + "</p>");
});
div#editable, div#demo {    border:1px solid gray;    padding:6px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div contenteditable="true" id="editable"></div>
<h3>Demo</h3><p>Copy this code and paste it on the editable div above:</p><div id="demo"> <p>This <b>is</b> <i>a</i> styled paragraph.</p> <p> </p> <p>The <span style="font-weight:bold">above paragraph</span> is empty.</p> <p>And this is a new paragraph…<br>with a line break!</p></div>

How can I pass make the text of a rich text box into a pre-defined variable in c#.net?

I needed to put all three lines into the same area. Thank you very much Igal!



Related Topics



Leave a reply



Submit