I need to "modify" all pasted into TextBox text to be shown in some structured way. I can do it with drag-n-drop, ctrl-v, but how to do it with default context's menu "Paste"?
1 Answer
While I would normally not suggest dropping to low level Windows API, and this may not be the only way of doing this, it does do the trick:
using System;
using System.Windows.Forms;
public class ClipboardEventArgs : EventArgs
{
public string ClipboardText { get; set; }
public ClipboardEventArgs(string clipboardText)
{
ClipboardText = clipboardText;
}
}
class MyTextBox : TextBox
{
public event EventHandler<ClipboardEventArgs> Pasted;
private const int WM_PASTE = 0x0302;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE)
{
var evt = Pasted;
if (evt != null)
{
evt(this, new ClipboardEventArgs(Clipboard.GetText()));
// don't let the base control handle the event again
return;
}
}
base.WndProc(ref m);
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var tb = new MyTextBox();
tb.Pasted += (sender, args) => MessageBox.Show("Pasted: " + args.ClipboardText);
var form = new Form();
form.Controls.Add(tb);
Application.Run(form);
}
}
Ultimately the WinForms toolkit is not very good. It is a thin-ish wrapper around Win32 and the Common Controls. It exposes the 80% of the API that is most useful. The other 20% is often missing or not exposed in a way that is obvious. I would suggest moving away from WinForms and to WPF if possible as WPF seems to be a better architected framework for .NET GUIs.
7 Comments
David
thanks, I've just learned sth new (not only how to catch "paste", nut a ne way of doin things)
Maxence
event keyword is missing on Pasted field declaration and why are you using a local variable evt ?
Mrchief
You're missing a
return inside the if statement which causes the base control to re-handle this event. I was formatting XML on paste and without the return, both the the formatted and unformatted XML show up as the base control handles the paste again.itsme86
@Maxence The local variable is to avoid a race condition that can occur between checking if
Pasted == null and invoking the handler. If the lone subscriber unsubscribes from the event on another thread between the check and invocation, you could end up with a null reference exception. C# 6 allows Pasted?.Invoke() as an alternative thead-safe solution.Chris Schaller
@itsme86 even in C#6 this capturing the variable is important because not only are we preventing the race condition, but we only want to prevent the default behaviour if the
Pasted event was registered in the first place. This implementation is therefore still relevant even as we head into C#10. |