我正在尝试拦截粘贴到WPF文本框中的数据。
例如,用户使用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);
}
}
使用上面的行为,当文本粘贴到TextBox中时,代码会被触发 但似乎TextBox不允许粘贴任何其他内容,因此如果它不是文本,它甚至都不会到达此代码。
我想知道,是否有需要在TextBox上设置的属性或其他内容 这将允许粘贴数据(即使TextBox永远不会显示该数据)
如果没有,那么哪些UI元素允许粘贴数据,因为我也可以将其用于我的优势。
更新 有人告诉我,我必须使用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();
}
}
}
这允许我将图像和文件粘贴到TextBox中,但仅限于此 使用CTRL + V键,而不是使用TextBox的默认上下文菜单。
所以我仍然有兴趣知道是否有更好/更简单的方式
更新2 基于Daniel的解决方案,该方法非常有效,我已经更新了OnAttached:
protected override void OnAttached()
{
base.OnAttached();
CommandManager.AddPreviewCanExecuteHandler(AssociatedObject, onPreviewCanExecute);
CommandManager.AddPreviewExecutedHandler(AssociatedObject, onPreviewExecuted);
}
删除了PreviewKeyDownHandler。
答案 0 :(得分:7)
您可以使用CommandManager.PreviewExecuted
和CommandManager.PreviewCanExecute
路由事件来处理您的粘贴逻辑。
例如,假设您想要在用户尝试将其粘贴到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;
}
}
}
然后,您必须将这些方法与路由事件相关联(例如,这可以在构造函数中):
CommandManager.AddPreviewExecutedHandler(myTextBox, onPreviewExecuted);
CommandManager.AddPreviewCanExecuteHandler(myTextBox, onPreviewCanExecute);
它应该适用于键盘快捷键和菜单“按钮”。
处理PreviewCanExecute事件非常重要。默认情况下,TextBox仅接受文本作为“可粘贴”内容,因此您需要以某种方式标记该内容以便粘贴它。
编辑: 此外,如果可以的话,最好从活动中删除“听众”。当您使用行为时,可以通过覆盖行为中的“OnDetaching”方法来实现。如果事件不是弱事件,这可以防止内存泄漏:
protected override void OnDetaching()
{
base.OnDetaching();
CommandManager.RemovePreviewExecutedHandler(myTextBox, onPreviewExecuted);
CommandManager.RemovePreviewCanExecuteHandler(myTextBox, onPreviewCanExecute);
}