wpf TextBox复制文字卡顿 和迅雷的冲突

迅雷会在后台一直监控读取用户剪切板,如果发现是下载格式,将会弹出下载框

在wpf的TextBox中,快速按Ctrl C会导致获取剪切板和设置剪切板的命令争抢引发System.Runtime.InteropServices.COMException
这个异常

通过查看源代码,发现在复制文字时,他们都不同情况的重试,暂停
这可能就导致了一直ctrl + c,一直:失败、暂停、重试、卡顿

这个情况,仅测试在wpf会存在,其他的文本框,vs 浏览器 记事本等等都没有出现这种情况

在winform中
System.Windows.Forms
public sealed class Clipboard

 /// <include file='doc\Clipboard.uex' path='docs/doc[@for="Clipboard.SetDataObject2"]/*' />
        /// <devdoc>
        /// <para>Overload that uses default values for retryTimes and retryDelay.</para>
        /// </devdoc>
        public static void SetDataObject(object data, bool copy) {
            SetDataObject(data, copy, 10 /*retryTimes*/, 100 /*retryDelay*/);
        }

在wpf中
System.Windows
public static class Clipboard

internal static void CriticalSetDataObject(object data, bool copy)

...
 while (true)
            {
                // Clear the system clipboard by calling OleSetClipboard with null parameter.
                int hr = OleServicesContext.CurrentOleServicesContext.OleSetClipboard(dataObject);
 
                if (NativeMethods.Succeeded(hr))
                {
                    break;
                }
 
                if (--i == 0)
                {
                    Marshal.ThrowExceptionForHR(hr);
                }
 
                Thread.Sleep(OleRetryDelay);
            }
 
            if (copy)
            {
                // Dev10 bug 835751 - OleSetClipboard and OleFlushClipboard both modify the clipboard
                // and cause notifications to be sent to clipboard listeners. We sleep a bit here to
                // mitigate issues with clipboard listeners (like TS) corrupting the clipboard contents
                // as a result of these two calls being back to back.
                Thread.Sleep(OleFlushDelay);
 
                Flush();
            }

尝试自己写一个复制,还是重试法,但他就不卡顿了

<TextBox CommandManager.PreviewExecuted="OnPreviewExecuted" Text="trykle test text" />
private void OnPreviewExecuted(object sender, ExecutedRoutedEventArgs e)
{
    if (e.Command == ApplicationCommands.Copy)
    {
        e.Handled = true;
    }
    SetClipboard(((TextBox)sender).SelectedText);
}

public void SetClipboard(string data)
{
    int times = 0;
    while (true)
    {
        times++;
        try
        {
            this.Dispatcher.Invoke(() =>
            {
                System.Windows.Clipboard.SetDataObject(data);
            });
            return;
        }
        catch (Exception ex)
        {
            Thread.Sleep(100);
            if (times > 10)
            {
                return;
            }
        }
    }
}
posted @ 2023-10-19 17:41  trykle  阅读(47)  评论(0编辑  收藏  举报