问题 检测富文本框内是否发生粘贴事件


有没有办法可以找出富文本框中是否发生剪贴板粘贴事件?此事件将用于使用粘贴的文本块执行某些操作。

谢谢

这是我的代码

 protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == WM_PASTE)
        {
            OnPasteOccurred();
            MessageBox.Show("Pas");
        }
        if (m.Msg == 0x000F)
        {
            if (PaintControl)
            {
                base.WndProc(ref m);
            }
            else
            {
                m.Result = IntPtr.Zero;
            }
        }
        else
        {
            base.WndProc(ref m);
        }
    }

编辑

我希望根据粘贴事件做一些语法高亮或缩进,这是特别的 代码编辑器 似乎做得非常有效。我不知道它是怎么做的。在这个特定方向需要帮助。我很确定必须有一些原生的Win32代码或类似的东西可以截取。我试过追踪键,鼠标事件并不漂亮。


3988
2018-04-11 07:32


起源

快速Web搜索显示RichTextBox不会通过向自身发送WM_PASTE来处理粘贴事件。所以我没有想法。 - David Heffernan
您可以将控件包装在您自己的自定义类中并覆盖 糊 方法。当然,这是假设在粘贴上调用方法。 - Brad Christie
嗯,在.NET 2.0中,你不能覆盖paste()方法,可能原因是由上面的@David给出的。 - redDragonzz
你不能只检查你的富文本控件是否有焦点,如果它有,那么粘贴在其中? - Pasi Savolainen


答案:


检测中的粘贴操作有点棘手 RichTextBox

第一种解决方案可能是检测 WM_PASTE 消息覆盖了 WndProc 但不幸的是,控件在执行粘贴操作时不会将该消息发送给自己。

天真的检测

要检测键盘事件可能有效(你必须覆盖 OnKeyDown 功能)然后检查键组合(CTRL+V 和 转移+INS)。像这样的东西:

protected override OnKeyDown(KeyEventArgs e)
{
     bool ctrlV = e.Modifiers == Keys.Control && e.KeyCode == Keys.V;
     bool shiftIns = e.Modifiers == Keys.Shift && e.KeyCode == Keys.Insert;

     if (ctrlV || shiftIns)
         DoSomething();
}

它运行良好,但您无法捕获使用鼠标进行的粘贴操作(右键单击以打开上下文菜单)以及通过拖放操作进行的粘贴操作。如果您不需要它们,您可以使用此解决方案(至少它简单明了)。

更好的检测

假设:当用户在里面输入时 RichTextBox 他每次插入一个字符。你怎么用这个?好吧,当您检测到更大的更改时,您检测到粘贴操作,因为用户每次不能输入多于一次的字符(好吧,您可以说因为Unicode代理而不是总是如此)。也可以看看 VB.NET版本 和 关于Unicode的更多细节 东东。

private int _previousLength = 0;

private void richTextBox_TextChanged(object sender, EventArgs e)
{
   int currentLength = richTextBox.Text.Length;
   if (Math.Abs(currentLength - _previousLength) > 1)
      ProcessAllLines();

   _previousLength = currentLength;
}

请注意,您不能(因为IME的工作方式不同)使用 OnKeyDown (或类似的)。这适用于西方语言,但它有Unicode的问题(因为,例如, String.Length 财产可能会增加两倍 Char 当用户键入单个字符时。也可以看看 这个帖子 关于这个的更多细节(即使 - 在这种情况下 - 你不关心它,这是一个强烈建议阅读甚至,)。在该帖子中,您还将找到用于确定字符串长度的更好算法的代码。总之,你必须替换:

   int currentLength = richTextBox.Text.Length;

有了这个:

   int currentLength = StringInfo.GetTextElementEnumerator(richTextBox.Text)
       .Cast<string>()
       .Count();

经过所有这些努力,您可能会意识到......用户甚至可以粘贴单个字符,但可能无法检测到。你是对的,这就是为什么这是一个原因 更好的检测 代替 完美解决方案

完美解决方案

当然存在完美的解决方案(如果你在Windows 8上运行),本机丰富的编辑控件发送一个 EN_CLIPFORMAT 通知消息。它旨在通知富编辑控件的父窗口,使用特定的剪贴板格式粘贴。然后你可以覆盖 WndProc其父母检测到的 WM_NOTIFY 此通知的消息。无论如何,这不是几行代码,请检查一下 MSDN文章 详情。


17
2018-04-12 11:36



是不是只应用于Windows 8的msdn? - redDragonzz
遗憾的是@redDragonzz ...是的,这只是Windows 8的通知消息。我会更新我的答案,以说清楚! - Adriano Repetti
@redDragonzz更新:我想一个“真正的”语法高亮算法不会因为性能不佳而受到影响,因为他不会对全文进行操作,并且在你输入时它会在另一个线程的后台进行。您是否看过(旧)SharpDevelop IDE的代码?他们确实提供了颜色和智能感知。 - Adriano Repetti
然而,上下文菜单在富文本框中不是标准的,也不是拖放。您可以完美地控制通过它完成的任何粘贴。据我所知,只有快捷方式确实需要检查。 - Nyerguds
@Nyerguds是的,它是!其实我喜欢那个话题(自我宣传: stackoverflow.com/a/27229590/1207195)但是,这是成千上万的问题和头痛的来源! - Adriano Repetti


从.Net 3.0开始,有一种内置的方法来检测粘贴事件:

DataObject.AddPastingHandler(this, OnPaste);

只需在构造函数中调用此方法即可。例如,如果您想要自己处理粘贴事件,就像用户手动输入文本一样,您可以使用

private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
    if (e.DataObject.GetDataPresent(typeof(string)))
    {
        var text = (string)e.DataObject.GetData(typeof(string));
        var composition = new TextComposition(InputManager.Current, this, text);
        TextCompositionManager.StartComposition(composition);
    }

    e.CancelCommand();
}

-2
2017-10-14 08:56



这个WPF不是winforms吗? - CodesInChaos
UPS。你是对的。没注意到标签...... - LionAM