允许“粘贴数据”到WPF文本框中

时间:2012-12-06 03:46:06

标签: c# wpf clipboard

我正在尝试拦截粘贴到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。

1 个答案:

答案 0 :(得分:7)

您可以使用CommandManager.PreviewExecutedCommandManager.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);
    }