Allow "insert data" into a WPF text box

I am trying to intercept data inserted into a WPF text box.

For example, a user creates a screen capture using the Windows shutdown tool, which automatically puts image data on the clipboard. The idea here is to allow the user to simply CTRL + V in the TextBox so that I can intercept it, check, and then do whatever I want with it.

public class PasteBehavior : Behavior<UIElement> { protected override void OnAttached() { base.OnAttached(); DataObject.AddPastingHandler(AssociatedObject, new DataObjectPastingEventHandler(OnPaste)); } protected override void OnDetaching() { base.OnDetaching(); } private void OnPaste(object sender, DataObjectPastingEventArgs e) { if (e.SourceDataObject.GetDataPresent(DataFormats.Text)) return; var formats = e.SourceDataObject.GetFormats(); foreach (var format in formats) Console.WriteLine(format); } } 

Using the above behavior, the code runs when the text is inserted into the TextBox, but it would seem that the TextBox does not allow you to insert anything else so that it never reaches this code if it is not text.

I am wondering if there is a property that needs to be set in a TextBox or something else that will allow data to be inserted (although a TextBox can never display this data)

If not, what user interface elements allow you to insert data, since I could use it to my advantage.

Update Someone sent me a message that I would have to use RichTextBox to allow embedding
for example, this is not something I can use, so I decided to take a different (somewhat hacked) approach:

 public class PasteBehavior : Behavior<UIElement> { protected override void OnAttached() { base.OnAttached(); AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown; } void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e) { if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) { if (Clipboard.ContainsData(DataFormats.Dib)) { using (var stream = new MemoryStream()) { var image = Clipboard.GetImage(); var message = new ImagePastedMessage() { ImageData = GetImagePngData(image) }; Messenger.Default.Send(message); } e.Handled = true; } else if (Clipboard.ContainsFileDropList()) { var results = Clipboard.GetFileDropList(); var filenames = new string[results.Count]; results.CopyTo(filenames, 0); var message = new FilesDroppedMessage() { Filenames = filenames }; Messenger.Default.Send(message); e.Handled = true; } } } protected override void OnDetaching() { base.OnDetaching(); } private byte[] GetImagePngData(BitmapSource source) { using (var stream = new MemoryStream()) { var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(source)); encoder.Save(stream); return stream.ToArray(); } } } 

This allows me to embed images and files in a TextBox, but only using the CTRL + V keys, not using the default context menu for the TextBox.

So I'm still curious to know if there is a better / easier way

Update 2 Based on Daniel's solution, which works very well, I updated OnAttached:

 protected override void OnAttached() { base.OnAttached(); CommandManager.AddPreviewCanExecuteHandler(AssociatedObject, onPreviewCanExecute); CommandManager.AddPreviewExecutedHandler(AssociatedObject, onPreviewExecuted); } 

And deleted PreviewKeyDownHandler.

+6
source share
1 answer

You can use CommandManager.PreviewExecuted and CommandManager.PreviewCanExecute routed events to handle your insertion logic.

For example, suppose you want to accept an image from the clipboard when a user tries to paste it into their TextBox. So, first define the methods that will handle both events:

  private void onPreviewCanExecute(object sender, CanExecuteRoutedEventArgs e) { // In this case, we just say it always can be executed (only for a Paste command), but you can // write some checks here if (e.Command == ApplicationCommands.Paste) { e.CanExecute = true; e.Handled = true; } } private void onPreviewExecuted(object sender, ExecutedRoutedEventArgs e) { // If it is a paste command.. if (e.Command == ApplicationCommands.Paste) { // .. and the clipboard contains an image if (Clipboard.ContainsImage()) { // proccess it somehow e.Handled = true; } } } 

Then you need to associate these methods with routed events (this could be, for example, in the constructor):

 CommandManager.AddPreviewExecutedHandler(myTextBox, onPreviewExecuted); CommandManager.AddPreviewCanExecuteHandler(myTextBox, onPreviewCanExecute); 

And it should work both with the keyboard shortcut and with the 'button' menu.

It is important to handle the PreviewCanExecute event. By default, a TextBox will only accept text as โ€œattachableโ€ content, so you need to mark this content somehow to insert it.

EDIT: Also, it is good practice to remove โ€œlistenersโ€ from this event, if you can. When you use a behavior, you can do this by overriding the OnDetaching method in your behavior. This can prevent a memory leak if events are not weak events:

  protected override void OnDetaching() { base.OnDetaching(); CommandManager.RemovePreviewExecutedHandler(myTextBox, onPreviewExecuted); CommandManager.RemovePreviewCanExecuteHandler(myTextBox, onPreviewCanExecute); } 
+7
source

All Articles