Custom paste behaviour for Windows Forms controls
Some Windows Forms controls come with copy/paste functionality out of the box. This is great when you just want the standard copy/paste behaviour, but what if you want to do some transformation of the data on the clipboard prior to displaying it in the Windows Forms control?
In my case I needed to convert a selection copied from Excel to a comma-delimited list of values when they were pasted in a TextBox. Since there is no OnPaste() method on the TextBox to override, I had to dig deeper to get the job done.
Usually something like this can be done by creating a subclass of the component and overriding the WndProc method to capture the right message. So I created a class called MyTextBox which extends TextBox and I trapped the windows Paste message, like this:
private const int WM_PASTE = 0x302; protected override void WndProc(ref Message m) { if (m.Msg == WM_PASTE) { // trigger our custom paste logic OnPaste(); } else { base.WndProc(ref m); } } protected virtual void OnPaste() { // put custom logic here }
There you go, now my own protected virtual OnPaste() method is called when the control receives a PASTE message, and the message is not passed to the base class to prevent the default paste behavior from being executed.
All that is left to do now is get the text data from the clipboard, do my own transformations and change the Text property of the TextBox accordingly.
Here is the full code for the MyTextBox class:
public class MyTextBox : TextBox { private const int WM_PASTE = 0x302; protected override void WndProc(ref Message m) { if (m.Msg == WM_PASTE) { OnPaste(); } else { base.WndProc(ref m); } } protected virtual void OnPaste() { string data = Clipboard.GetData(DataFormats.Text) as string; if (data != null) { string convertedText = DelimitByCommas(data); InsertText(convertedText); } } protected virtual string DelimitByCommas(string text) { text = text.Replace("\r\n", ","); text = text.Replace("\t", ","); return text.Trim(',', ' '); } protected virtual void InsertText(string textToInsert) { int selectionEnd = SelectionStart + SelectionLength; int newCaretPos = SelectionStart + textToInsert.Length; string prefix = Text.Substring(0, SelectionStart); string suffix = Text.Substring(selectionEnd, Text.Length - selectionEnd); Text = prefix + textToInsert + suffix; // position the caret at the end of the pasted text SelectionStart = newCaretPos; } }
Saturday 03 Mar 2007 | Guy Mahieu | .net(t) , c#(t) , tips&tricks(t) , winforms(t)
Excellent little piece of code - I wanted to prevent users from pasting non-numeric characters into a textbox. Your override showed me exactly how to do it.
What if you wanted to capture the paste command globally, regardless of which app it occurred in, and manipulate the data. Do you know how to do this?
You’d need a message filter for that. Check out: http://blogs.msdn.com/csharpfaq/archive/2004/10/20/245412.aspx
Does that do what you need?