【问题标题】:Detecting if paste event occurred inside a rich text box检测是否在富文本框中发生粘贴事件
【发布时间】:2011-04-11 07:32:14
【问题描述】:

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

谢谢

这是我的代码

 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);
        }
    }

编辑

我希望根据粘贴事件进行一些语法高亮或缩进,这个特定的code editor 似乎非常有效。我不知道它是如何做到的。在这个特定方向上需要帮助。我很确定必须有一些本机 Win32 代码或类似的东西可以被拦截。我尝试过跟踪键、鼠标事件,但它并不漂亮。

【问题讨论】:

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

标签: c# .net winforms richtextbox


【解决方案1】:

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

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

幼稚检测

要检测键盘事件可能有效(您必须覆盖OnKeyDown 函数)然后检查组合键(CTRL+VSHIFT +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 versionmore details about 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。另请参阅 this post 了解更多详情(好吧,即使是强烈建议阅读,即使 - 在这种情况下 - 你不关心它)。在那篇文章中,您还将找到用于确定字符串长度的更好算法的代码。简而言之,您必须替换:

   int currentLength = richTextBox.Text.Length;

有了这个:

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

经过所有这些努力,您可能会意识到……用户甚至可以粘贴单个字符,但它可能未被检测到。你是对的,这就是为什么这是一个更好的检测,而不是一个完美的解决方案

完美解决方案

当然存在完美的解决方案(如果您在 Windows 8 上运行),原生富编辑控件会发送EN_CLIPFORMAT 通知消息。它旨在通知 Rich Edit 控件的父窗口发生了特定剪贴板格式的粘贴。然后,您可以覆盖其父级的 WndProc 以检测此通知的 WM_NOTIFY 消息。反正不是几行代码,详情请查看MSDN article

【讨论】:

  • 不是msdn只适用于windows 8吗?
  • @redDragonzz 很遗憾...是的,这是仅适用于 Windows 8 的通知消息。我会更新我的答案以明确表示!
  • @redDragonzz 更新:我猜“真正的”语法高亮算法不会因性能不佳而受到影响,因为他不会处理全文,它会在另一个线程的后台执行在你打字的时候。你看过(旧的)SharpDevelop IDE 的代码吗?它们确实提供了颜色和智能感知。
  • 上下文菜单在富文本框中不是标准的,拖放也不是。您可以完美地控制通过它完成的任何粘贴。据我所知,只有捷径真正需要检查。
  • @Nyerguds 是的,是的!实际上我喜欢这个话题(自我广告:stackoverflow.com/a/27229590/1207195),但是是的,它是成千上万的问题和头痛的根源!
【解决方案2】:

从.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();
}

【讨论】:

  • 这个WPF不是winforms吗?
【解决方案3】:

我遇到了这个老问题,我想分享我的解决方案(它是 VB,但可以轻松转换)。我在需要时使用它强制粘贴为纯文本:

Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
    If ForcePasteAsPlainText And ((e.Control = True And e.KeyCode = Keys.V) Or (e.Shift = True And e.KeyCode = Keys.Insert)) Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
        e.Handled = True
        Return
    End If
    MyBase.OnKeyDown(e)
End Sub

Shadows Sub Paste()
    If ForcePasteAsPlainText Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
    Else
        MyBase.Paste()
    End If
End Sub

Shadows Sub Paste(clipFormat As DataFormats.Format)
    If ForcePasteAsPlainText Then
        MyBase.Paste(DataFormats.GetFormat(DataFormats.Text))
    Else
        MyBase.Paste(clipFormat)
    End If
End Sub

【讨论】:

    猜你喜欢
    • 2015-08-18
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多