剪贴板监听事件被调用了两次。

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

使用

    [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() 函数有时会被调用两次或三次。
我认为这些应用程序可能会使用不同的格式将数据写入剪贴板,这就是为什么该函数会被调用多次的原因。 但是,我该如何防止重复保存相同的数据,因为 OnClipboardChanged() 被多次调用?

在Message(m)参数上是否有一个属性,对于每个写入剪贴板的实例都是相同的?也许有一个ID吗?如果是这样的话,如果您已经处理过该消息/ID,那么您可以忽略该消息。 - Bob Horn
嗨,Bob, 我找不到有关消息ID或类似内容的任何信息...这是一个非常好的想法,如果每个消息都有一个“呼叫ID”就太棒了,无论如何谢谢。 - lebhero
2个回答

9
因为它们多次打开/关闭剪贴板。我以前见过这种疯狂的情况。Excel在复制图表时执行了24个单独的操作。
与其使用以下伪代码:
openClipboard
for each format {
  place data on clipboard(format)
}
closeClipboard

他们很可能正在做这件事情:
for each format {
  openClipboard
  place data on clipboard(format)
  closeClipboard
}

更新:通常的缓解策略是避免对每个更新做出反应,并在经过合理的“安定时间”后对最后一个更新做出反应,而且没有更多的剪贴板通知。 500毫秒通常足够了。

嗨,谢谢你的回答。我该如何确保只调用一次函数?如果剪贴板中的数据没有更改,但已像你上面说的那样被重写,我该如何检查?我只想保存可用的HTML,如果不可用,则需要获取文本。但是,像你提到的那样重新编写剪贴板有时会调用两次甚至三次函数,所以我无法确定是否必须保存剪贴板中的数据! - lebhero
事件处理程序将针对每个剪贴板更新(通常为WM_DrawClipboard消息)调用一次。唯一使其仅被调用一次的方法是更正执行更新的程序,而这超出了您的控制范围。请参见我上面的更新以获取缓解策略。 - Chris Thornton
感谢 Chris.. 我将接受你的答案,因为它似乎是唯一可行的方法... 感谢你的想法.. - lebhero
1
WM_DrawClipboard事件的行为不正确。请勿使用。 - amilamad

1

防止多次调用剪贴板

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

1
感谢您的发帖,但是所有在Stack Overflow上的帖子都必须使用英语。请参见此处了解详情。 - Joey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接