允许“粘贴数据”到 WPF 文本框
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13736626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Allowing 'pasting data' into a WPF textbox
提问by TimothyP
I'm trying to intercept data pasted into a WPF textbox.
我正在尝试拦截粘贴到 WPF 文本框中的数据。
For example, the user creates a screen capture with the Windows snipping tool, which automatically places the image data on the clipboard. The idea here is to allow the user to simply CTRL+V on the TextBox so that I can intercept it, check if it's data and then do whatever I want with it.
例如,用户使用 Windows 截图工具创建屏幕截图,该工具会自动将图像数据放在剪贴板上。这里的想法是允许用户在 TextBox 上简单地按 CTRL+V 以便我可以拦截它,检查它是否是数据,然后对它做任何我想做的事情。
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 behavior above, the code does get triggered when text is pasted into the TextBox but it would seem the TextBox does not allow anything else to be pasted so it never even reaches this code if it's not text.
使用上述行为,当文本粘贴到 TextBox 时,代码确实被触发,但似乎 TextBox 不允许粘贴任何其他内容,因此如果它不是文本,它甚至永远不会到达此代码。
I'm wondering, is there a property that needs to be set on the TextBox, or something else that would allow data to be pasted (even though the TextBox can never display that data)
我想知道,是否有需要在 TextBox 上设置的属性,或者其他允许粘贴数据的属性(即使 TextBox 永远无法显示该数据)
If not, what UI elements do allow data to be pasted, as I might be able to use that to my advantage as well.
如果没有,哪些 UI 元素确实允许粘贴数据,因为我也可以利用它。
UpdateSomeone posted out to me that I'd have to use a RichTextBox to allow pasting
like this, which is not something I can use, so I decided to take a different (somewhat hacky) approach:
更新有人告诉我,我必须使用 RichTextBox 来允许
像这样粘贴,这不是我可以使用的,所以我决定采用不同的(有点 hacky)方法:
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 paste images and files into the TextBox but only using the CTRL+V keys, not using the default context menu of the TextBox.
这允许我将图像和文件粘贴到文本框,但只能使用 CTRL+V 键,而不是使用文本框的默认上下文菜单。
So I'm still interested in knowing if there is a better/easier way
所以我仍然有兴趣知道是否有更好/更简单的方法
Update 2Based on the solution by Daniel, which works really well, I've updated the OnAttached:
更新 2基于 Daniel 的解决方案,效果非常好,我更新了 OnAttached:
protected override void OnAttached()
{
base.OnAttached();
CommandManager.AddPreviewCanExecuteHandler(AssociatedObject, onPreviewCanExecute);
CommandManager.AddPreviewExecutedHandler(AssociatedObject, onPreviewExecuted);
}
And removed the PreviewKeyDownHandler.
并删除了 PreviewKeyDownHandler。
回答by Daniel Castro
You can use CommandManager.PreviewExecutedand CommandManager.PreviewCanExecuterouted events to handle your pasting logic.
您可以使用CommandManager.PreviewExecuted和CommandManager.PreviewCanExecute路由事件来处理您的粘贴逻辑。
For example, let's suppose you want to accept an image from the clipboard when a user tries to paste it into your TextBox. So first, define the methods that will handle both events:
例如,假设您希望在用户尝试将剪贴板中的图像粘贴到您的 TextBox 时接受该图像。因此,首先,定义将处理这两个事件的方法:
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 have to associate those methods with the routed events (this could go in the constructor, for example):
然后,您必须将这些方法与路由事件相关联(例如,这可以在构造函数中进行):
CommandManager.AddPreviewExecutedHandler(myTextBox, onPreviewExecuted);
CommandManager.AddPreviewCanExecuteHandler(myTextBox, onPreviewCanExecute);
And it should work with both the keyboard shortcut and the menu 'button'.
它应该适用于键盘快捷键和菜单“按钮”。
It is important to handle the PreviewCanExecute event. By default, the TextBox will only accept text as a 'pasteable' content, so you need to mark that content somehow in order to paste it.
处理 PreviewCanExecute 事件很重要。默认情况下,TextBox 只接受文本作为“可粘贴”内容,因此您需要以某种方式标记该内容以粘贴它。
EDIT: Also, it is a good practice to remove the 'listeners' from the event if you can. As you're using behaviors, you can do this by overriding the 'OnDetaching' method in your behavior. This could prevent memory leaks if the events are not Weak Events:
编辑:另外,如果可以的话,从事件中删除“听众”是一个很好的做法。当您使用行为时,您可以通过覆盖行为中的“OnDetaching”方法来实现。如果事件不是弱事件,这可以防止内存泄漏:
protected override void OnDetaching()
{
base.OnDetaching();
CommandManager.RemovePreviewExecutedHandler(myTextBox, onPreviewExecuted);
CommandManager.RemovePreviewCanExecuteHandler(myTextBox, onPreviewCanExecute);
}

