【问题标题】:clipboard Listener event is being called twice剪贴板监听器事件被调用两次
【发布时间】:2012-04-29 16:17:49
【问题描述】:

我想将更改保存在我的剪贴板中。所以我注册了我的应用程序以获取剪贴板发生的所有更改。

使用

    [DllImport("User32.dll")]
    protected static extern bool AddClipboardFormatListener(int hwnd);

然后

protected override void WndProc(ref Message m)
    {
switch (m.Msg)
        {
            case WM_CLIPBOARDUPDATE:
                OnClipboardChanged();
                break;
             ...
        }
     }

private void OnClipboardChanged()
{
    if (Clipboard.ContainsText())
        {
         MessageBox.Show(Clipboard.GetText().ToString());
        }
}

问题是: 从 Visual Studio 或 firefox 等应用程序复制文本时,有时会调用 OnClipboardChanged() 函数两次或 3 次。

我认为那些应用程序会以不同的格式将数据写入剪贴板,这就是该函数被多次调用的原因。 但是我如何防止保存相同的数据,因为 OnClipboardChanged() 被多次调用?

【问题讨论】:

  • Message (m) 参数上是否有一个属性对于写入剪贴板的每个实例都相同?也许是身份证?如果是这样,如果您已经处理了该消息/ID,也许您可​​以忽略该消息?
  • 嗨,鲍勃,我找不到任何关于 msg id 或类似的东西..这是一个真正的好主意,如果每个 msg 都有一个“呼叫 id”,那就太好了,谢谢跨度>

标签: c# clipboard


【解决方案1】:

因为他们多次打开/关闭剪贴板。我以前见过这样的疯狂。 Excel 用于在复制图表时执行 24 种单独的操作。
而不是这个(伪代码):

openClipboard
for each format {
  place data on clipboard(format)
}
closeClipboard

他们可能正在这样做:

for each format {
  openClipboard
  place data on clipboard(format)
  closeClipboard
}

更新:通常的缓解策略是避免对每次更新做出反应,并在经过合理的“稳定时间”后对最后一次更新做出反应,并且没有进一步的剪贴板通知。 500 毫秒通常绰绰有余。

【讨论】:

  • 嗨..谢谢您的回答...我如何确保我只调用一次函数?我将如何检查剪贴板中的数据是否没有改变,但是像你上面说的那样被重写了?我只想保存 html(如果可用),如果没有,我需要获取文本 .. 但是重写剪贴板正如你提到的那样有时会调用该函数两次甚至 3 次,所以我无法决定是否必须保存数据是否出现在剪贴板中!?
  • 每次剪贴板更新都会调用一次偶数处理程序(通常是 WM_DrawClipboard 消息)。让它调用一次的唯一方法是更正执行更新的程序,这超出了您的控制范围。请参阅上面的更新以了解缓解策略。
  • 感谢 chris ..我会接受您的回答,因为这似乎是唯一可行的方法...感谢您的想法..
  • WM_DrawClipboard 事件行为不正确。不要用那个。
【解决方案2】:

防止多次调用剪贴板

private int _i = 0;
private int i
{
    get
    {
        async void setI()
        {
            await Task.Run(() =>
            {
                Thread.Sleep(20);
                i = 0;
            }
            );
        }
        setI();
        return _i;
    }
    set
    {
        _i = value;
    }
}
private IntPtr HwndHandler(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
    if (msg == WM_CLIPBOARDUPDATE)
    {
        if(i<1)
        {
            this.ClipboardUpdate?.Invoke(this, new EventArgs());
            i++;
        }
    }
    handled = false;
    return IntPtr.Zero;
}

【讨论】:

  • 感谢您发布此内容,但所有有关堆栈溢出的帖子都必须使用英文。详情请见here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多