当从WPF数据网格复制粘贴数据时,OpenClipboard失败

时间:2021-12-10 09:23:18

I've got a WPF application using datagrid. The application worked fine until I installed Visual Studio 2012 and Blend+SketchFlow preview. Now, when I'm trying to copy the data from the grid into the clipboard with Ctrl + C (in any application), I'm getting the following exception:

我有一个使用datagrid的WPF应用程序。这个应用程序运行良好,直到我安装了Visual Studio 2012和Blend+SketchFlow preview。现在,当我尝试用Ctrl + C将数据从网格复制到剪贴板(在任何应用程序中)时,我遇到了以下例外:

System.Runtime.InteropServices.COMException (0x800401D0): OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN))
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode, IntPtr errorInfo)
   at System.Windows.Clipboard.Flush()
   at System.Windows.Clipboard.CriticalSetDataObject(Object data, Boolean copy)
   at System.Windows.Controls.DataGrid.OnExecutedCopy(ExecutedRoutedEventArgs args)
   at System.Windows.Controls.DataGrid.OnExecutedCopy(Object target, ExecutedRoutedEventArgs args)
   at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
   at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated)
   at System.Windows.Input.RoutedCommand.ExecuteCore(Object parameter, IInputElement target, Boolean userInitiated)
   at System.Windows.Input.CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs)
   at System.Windows.UIElement.OnKeyDownThunk(Object sender, KeyEventArgs e)
   at System.Windows.Input.KeyEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawKeyboardActions actions, Int32 scanCode, Boolean isExtendedKey, Boolean isSystemKey, Int32 virtualKey)
   at System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(MSG& msg, Boolean& handled)
   at System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(MSG& msg, ModifierKeys modifiers)
   at System.Windows.Interop.HwndSource.OnPreprocessMessage(Object param)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
   at System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(MSG& msg, Boolean& handled)
   at System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(MSG& msg, Boolean& handled)
   at System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()

This is really annoying.

这真的很烦人。

I've seen some references to this problem here and on various locations on the web, with no real solution.

我在这里和web上的不同位置看到了一些关于这个问题的引用,但是没有真正的解决方案。

I can verify that the clipboard is locked when this exception is raised in Visual Studio, as I couldn't copy paste the message (had to write it to a file). Also, the clipboard wasn't locked before the copy process started.

当在Visual Studio中引发此异常时,我可以验证剪贴板是否被锁定,因为我无法复制粘贴消息(必须将其写入文件)。此外,剪贴板在复制过程开始之前没有被锁定。

How to solve this problem?

如何解决这个问题?

9 个解决方案

#1


69  

We are using .NET 4.0. We had the same problem, but after logging off the system, code used to work fine for some time.

我们正在使用。net 4.0。我们遇到了同样的问题,但是在注销系统之后,代码在一段时间内正常工作。

Finally we found the alternative.

最后我们找到了另一种选择。

If you want to copy a string to the clipboard,

如果要将字符串复制到剪贴板,

string data = "Copy This"

Till now I was using the following method

到目前为止,我一直在使用以下方法

Clipboard.SetText(data);

It was failing again and again. Then I looked at other methods available to set text in the clipboard in Clipboard Class and tried the following:

它一次又一次地失败。然后我查看了剪贴板类中用于设置剪贴板文本的其他方法,并尝试了以下方法:

Clipboard.SetDataObject(data);

And it worked :). I never had the issue again.

和它工作:)。我再也没有这个问题了。

#2


65  

It is a bug in the WPF Clipboard handler. You need to handle the unhandled exception in the Application.DispatcherUnhandledException event.

这是WPF剪贴板处理程序中的一个错误。您需要在应用程序中处理未处理的异常。DispatcherUnhandledException事件。

Add this attribute to the Application element in your App.xaml

将此属性添加到App.xaml中的应用程序元素。

DispatcherUnhandledException="Application_DispatcherUnhandledException"

Add this code to your App.xaml.cs file

将此代码添加到App.xaml。cs文件

void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    var comException = e.Exception as System.Runtime.InteropServices.COMException;

    if (comException != null && comException.ErrorCode == -2147221040)
         e.Handled = true;
}

#3


5  

I, too, have been having a problem in an application where I copy information into the clipboard as users peruse a ListBox. The information that's copied is related to the selected item, and it permits them to paste it (said info) into other applications for convenience. Occasionally I get the CLIPBRD_E_CANT_OPEN on some user's systems, but not on others.

我在一个应用程序中也遇到了问题,当用户仔细阅读列表框时,我将信息复制到剪贴板中。被复制的信息与所选择的项相关,它允许它们将它(said info)粘贴到其他应用程序中,以方便使用。有时,我在某些用户的系统上获得CLIPBRD_E_CANT_OPEN,但在其他系统上没有。

While I still haven't been able to fix the contention, I was able to create some code to find the application causing the contention. I'd like to at least share this code in the hope it helps someone. I will add the using statement, attributes, and method I created to find the Process object of the culprit. From the Process item you can obtain the process' name, PID, main window title (if it has one), and other potentially useful data. Here's the lines of code I added without the code that calls it. (NOTE: Below the code snippet I have one more tidbit to share):

虽然我仍然无法修复争用,但是我可以创建一些代码来查找引起争用的应用程序。我想至少分享一下这段代码,希望它能对某些人有所帮助。我将添加我创建的use语句、属性和方法来查找罪魁祸首的流程对象。从流程项中可以获取流程的名称、PID、主窗口标题(如果有的话)和其他可能有用的数据。这是我添加的代码行,没有调用它的代码。(注:在代码片段下面,我还有一个小细节要分享):

using System.Diagnostics;               // For Process class
using System.Runtime.InteropServices;   // For DllImport's

...

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetOpenClipboardWindow();

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

...

    ///-----------------------------------------------------------------------------
    /// <summary>
    /// Gets the Process that's holding the clipboard
    /// </summary>
    /// <returns>A Process object holding the clipboard, or null</returns>
    ///-----------------------------------------------------------------------------
    public Process ProcessHoldingClipboard()
    {
        Process theProc = null;

        IntPtr hwnd = GetOpenClipboardWindow();

        if (hwnd != IntPtr.Zero)
        {
            uint processId;
            uint threadId = GetWindowThreadProcessId(hwnd, out processId);

            Process[] procs = Process.GetProcesses();
            foreach (Process proc in procs)
            {
                IntPtr handle = proc.MainWindowHandle;

                if (handle == hwnd)
                {
                    theProc = proc;
                }
                else if (processId == proc.Id)
                {
                    theProc = proc;
                }
            }
        }

        return theProc;
    }

OTHER NOTE: One other thing I changed which simplified my code a bit was to convert from using System.Windows.Clipboard to System.Windows.Forms.Clipboard (see System.Windows.Forms.Clipboard Class)because the latter has a 4-parameter SetDataObject() method which includes a retry count and a retry delay in milliseconds. This at least removed some of the retry noise from my code.

其他注意:我还修改了一件使代码简化了一点的事情,那就是从System.Windows中进行转换。System.Windows.Forms剪贴板。剪贴板(见System.Windows.Forms。Clipboard类),因为后者有一个4参数的SetDataObject()方法,其中包括重试计数和重试延迟(毫秒)。这至少消除了我代码中的一些重试噪音。

Your mileage may vary...plus there may be side effects in this which I've not yet stumbled upon, so if anyone knows of them please comment. In any event, I hope this proves useful to someone.

你的情况可能不同……另外,我还没有发现这方面的副作用,所以如果有人知道,请评论。无论如何,我希望这对某人有用。

#4


5  

I also had this issue in WPF 4.0 and 4.5 since I installed TeraCopy (Windows 7, 64-bit). Every Clipboard.SetText() failed with a System.Runtime.InteropServices.COMException.

我在WPF 4.0和4.5中也有这个问题,因为我安装了TeraCopy (Windows 7, 64位)。每个Clipboard.SetText()在System.Runtime.InteropServices.COMException中失败。

My first solution was to uninstall TeraCopy - it worked, but I love this application, so I had to search for another solution to resolve that issue. The solution was to replace

我的第一个解决方案是卸载TeraCopy——它可以工作,但是我喜欢这个应用程序,所以我必须寻找另一个解决方案来解决这个问题。解决办法是替换

Clipboard.SetText("my string");

with

Clipboard.SetDataObject("my string");

#5


2  

I had the same problem with RichTextBox. The following code crashed randomly:

我对RichTextBox也有同样的问题。以下代码随机崩溃:

TextRange tr = new TextRange(rich.Document.ContentStart, rich.Document.ContentEnd);
System.Windows.Clipboard.SetDataObject(tr.Text);

It seems it's preferred to use System.Windows.Controls.RichTextBox.Copy

它似乎更喜欢使用System.Windows.Controls.RichTextBox.Copy

#6


2  

I had a problem to retrieve XAML data from the clipboard with .NET 4.6.1.

我在使用。net 4.6.1从剪贴板中检索XAML数据时遇到了一个问题。

Error message:

错误信息:

OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)))

OpenClipboard失败(HRESULT中的异常:0x800401D0 (CLIPBRD_E_CANT_OPEN))

I solved it as follows:

我解出如下:

int counter = 0;
object xamlClipData = null;

while (xamlClipData == null)
{
    try
    {
        if (counter > 10)
        {
            System.Windows.MessageBox.Show("No access to clipboard xaml data.");
            break;
        }

        counter++;

        if (System.Windows.Clipboard.GetDataObject().GetDataPresent(DataFormats.Xaml))
        {
            xamlClipData = System.Windows.Clipboard.GetData(DataFormats.Xaml);
        }
    }
    catch { }
}

#7


1  

I had the same problem in copying Excel cells to the clipboard and getting data from the clipboard as an HTML string.

我在将Excel单元格复制到剪贴板并作为HTML字符串从剪贴板获取数据时遇到了同样的问题。

You can use (while-try-catch) like in the below code.

您可以使用(while-try-catch),如下面的代码所示。

Excel.Application exap = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook wb = exap.Workbooks.Open(
                      sourceFileNameTextBox.Text,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing);
Excel.Sheets sh = wb.Worksheets;

bool clip = false;

// Copy Excel cells to clipboard
while (!clip)
{
    try
    {
        ws.Cells.get_Range(cells[0], cells[1]).Copy(Type.Missing);
        clip = true;
    }
    catch
    {
        clip = false;
    }
}

string b = "";

// Get Excel cells data from the clipboard as HTML

clip = false;
while(!clip)
{
    try
    {
        b = Clipboard.GetData(DataFormats.Html) as string;
        clip = true;
    }
    catch
    {
        clip = false;
    }
}

Also, you can have a counter in the while if the loop is more than 10 times or more, exception occur. I test its maximum counter is one and in one time loop clipboard work.

此外,如果循环次数超过10次或更多,则可以在while中使用计数器,这时会发生异常。我测试它的最大计数器是1,在一个时间循环剪贴板工作。

#8


0  

There's a DataGrid event/method signature for this exact purpose CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e) and is more reliable than Clipboard.SetDataObject(data) or Clipboard.SetText(data).

对于这个目的,有一个DataGrid事件/方法签名CopyingRowClipboardContent(对象发送方、datagrisleepclipboardeventargs e),它比剪贴板. setdataobject (data)或剪贴板. settext (data)更可靠。

Here's how to use it.

下面是如何使用它的方法。

Set "FullRow" at the SelectionUnit mode for dataGrid called myDataGrid

将“FullRow”设置为dataGrid的选择单元模式为myDataGrid

<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>

We have a method, myDataGrid_CopyingRowClipboardContent, that gets called for each row in the dataGrid to copy its contents to the clipboard. For example,for a datagrid with seven rows this is called seven times.

我们有一个方法,myDataGrid_CopyingRowClipboardContent,它为dataGrid中的每一行调用,将其内容复制到剪贴板。例如,对于有7行的datagrid,这被称为7次。

public int clipboardcalledcnt { get; set; } // CopyingRowClipboardContent invoked count
private void myDataGrid_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
    PathInfo cellpath = new PathInfo(); // A custom class to hold path information
    string path = string.Empty;

    DataGrid dgdataPaths = (DataGrid)sender;
    int rowcnt = dgdataPaths.SelectedItems.Count;

    cellpath = (PathInfo)e.Item;

    path = "Row #" + clipboardcalledcnt + " Len=" + cellpath.Length.ToString() + ", path=" + cellpath.Path;

    e.ClipboardRowContent.Clear();

    if (clipboardcalledcnt == 0) // Add header to clipboard paste
        e.ClipboardRowContent.Add(new DataGridClipboardCellContent("", null, "--- Clipboard Paste ---\t\t\n")); // \t cell divider, repeat (number of cells - 1)

    clipboardcalledcnt++;
    e.ClipboardRowContent.Add(new DataGridClipboardCellContent(path, null, path));

    if (clipboardcalledcnt == rowcnt)
        clipboardcalledcnt = 0;
}

#9


0  

Adding my answer from mentioned SO question for reference -

增加我从上述问题的回答作为参考-

Found this from Andrew Smith at http://blogs.infragistics.com/forums/t/35379.aspx -

在http://blogs.infragistics.com/forums/t/35379.aspx -上找到这篇文章

Technically only 1 process can open the clipboard so if another process has it opened the subsequent requests will fail until the first releases the clipboard. This was sort of handled in the WinForms Clipboard class where it would retry the set with a delay in between each try but the WPF clipboard class doesn't do this so if it fails on the first show the exception occurs. Even then we should probably catch the exception and raise the clipboard operation error if it still fails.

从技术上讲,只有一个进程可以打开剪贴板,所以如果另一个进程打开了剪贴板,那么在第一个进程释放剪贴板之前,后续的请求将会失败。这是在WinForms剪贴板类中处理的,在这个类中,每次尝试之间都会有一个延迟,但是WPF剪贴板类不会这么做,所以如果它在第一次出现异常时失败了。即使这样,如果异常仍然失败,我们也应该捕获异常并抛出剪贴板操作错误。

Same thing is explained and some ways to fix it are mentioned on this italian blog -

同样的事情被解释和一些解决它的方法被提到在这个意大利的博客上-

WPF DataGrid Clipboard BUG (?) & Work (Cached translation) (Orignal Link)

WPF DataGrid剪贴板BUG(?)和Work(缓存翻译)(Orignal链接)

Following MSDN forum thread suggests that this could be machine specific problem -

根据MSDN论坛提示,这可能是机器特有的问题

CLIPBRD_E_CANT_OPEN exception when copying to clipboard from a DataGrid

当从DataGrid复制到剪贴板时,CLIPBRD_E_CANT_OPEN异常。

#1


69  

We are using .NET 4.0. We had the same problem, but after logging off the system, code used to work fine for some time.

我们正在使用。net 4.0。我们遇到了同样的问题,但是在注销系统之后,代码在一段时间内正常工作。

Finally we found the alternative.

最后我们找到了另一种选择。

If you want to copy a string to the clipboard,

如果要将字符串复制到剪贴板,

string data = "Copy This"

Till now I was using the following method

到目前为止,我一直在使用以下方法

Clipboard.SetText(data);

It was failing again and again. Then I looked at other methods available to set text in the clipboard in Clipboard Class and tried the following:

它一次又一次地失败。然后我查看了剪贴板类中用于设置剪贴板文本的其他方法,并尝试了以下方法:

Clipboard.SetDataObject(data);

And it worked :). I never had the issue again.

和它工作:)。我再也没有这个问题了。

#2


65  

It is a bug in the WPF Clipboard handler. You need to handle the unhandled exception in the Application.DispatcherUnhandledException event.

这是WPF剪贴板处理程序中的一个错误。您需要在应用程序中处理未处理的异常。DispatcherUnhandledException事件。

Add this attribute to the Application element in your App.xaml

将此属性添加到App.xaml中的应用程序元素。

DispatcherUnhandledException="Application_DispatcherUnhandledException"

Add this code to your App.xaml.cs file

将此代码添加到App.xaml。cs文件

void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    var comException = e.Exception as System.Runtime.InteropServices.COMException;

    if (comException != null && comException.ErrorCode == -2147221040)
         e.Handled = true;
}

#3


5  

I, too, have been having a problem in an application where I copy information into the clipboard as users peruse a ListBox. The information that's copied is related to the selected item, and it permits them to paste it (said info) into other applications for convenience. Occasionally I get the CLIPBRD_E_CANT_OPEN on some user's systems, but not on others.

我在一个应用程序中也遇到了问题,当用户仔细阅读列表框时,我将信息复制到剪贴板中。被复制的信息与所选择的项相关,它允许它们将它(said info)粘贴到其他应用程序中,以方便使用。有时,我在某些用户的系统上获得CLIPBRD_E_CANT_OPEN,但在其他系统上没有。

While I still haven't been able to fix the contention, I was able to create some code to find the application causing the contention. I'd like to at least share this code in the hope it helps someone. I will add the using statement, attributes, and method I created to find the Process object of the culprit. From the Process item you can obtain the process' name, PID, main window title (if it has one), and other potentially useful data. Here's the lines of code I added without the code that calls it. (NOTE: Below the code snippet I have one more tidbit to share):

虽然我仍然无法修复争用,但是我可以创建一些代码来查找引起争用的应用程序。我想至少分享一下这段代码,希望它能对某些人有所帮助。我将添加我创建的use语句、属性和方法来查找罪魁祸首的流程对象。从流程项中可以获取流程的名称、PID、主窗口标题(如果有的话)和其他可能有用的数据。这是我添加的代码行,没有调用它的代码。(注:在代码片段下面,我还有一个小细节要分享):

using System.Diagnostics;               // For Process class
using System.Runtime.InteropServices;   // For DllImport's

...

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetOpenClipboardWindow();

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

...

    ///-----------------------------------------------------------------------------
    /// <summary>
    /// Gets the Process that's holding the clipboard
    /// </summary>
    /// <returns>A Process object holding the clipboard, or null</returns>
    ///-----------------------------------------------------------------------------
    public Process ProcessHoldingClipboard()
    {
        Process theProc = null;

        IntPtr hwnd = GetOpenClipboardWindow();

        if (hwnd != IntPtr.Zero)
        {
            uint processId;
            uint threadId = GetWindowThreadProcessId(hwnd, out processId);

            Process[] procs = Process.GetProcesses();
            foreach (Process proc in procs)
            {
                IntPtr handle = proc.MainWindowHandle;

                if (handle == hwnd)
                {
                    theProc = proc;
                }
                else if (processId == proc.Id)
                {
                    theProc = proc;
                }
            }
        }

        return theProc;
    }

OTHER NOTE: One other thing I changed which simplified my code a bit was to convert from using System.Windows.Clipboard to System.Windows.Forms.Clipboard (see System.Windows.Forms.Clipboard Class)because the latter has a 4-parameter SetDataObject() method which includes a retry count and a retry delay in milliseconds. This at least removed some of the retry noise from my code.

其他注意:我还修改了一件使代码简化了一点的事情,那就是从System.Windows中进行转换。System.Windows.Forms剪贴板。剪贴板(见System.Windows.Forms。Clipboard类),因为后者有一个4参数的SetDataObject()方法,其中包括重试计数和重试延迟(毫秒)。这至少消除了我代码中的一些重试噪音。

Your mileage may vary...plus there may be side effects in this which I've not yet stumbled upon, so if anyone knows of them please comment. In any event, I hope this proves useful to someone.

你的情况可能不同……另外,我还没有发现这方面的副作用,所以如果有人知道,请评论。无论如何,我希望这对某人有用。

#4


5  

I also had this issue in WPF 4.0 and 4.5 since I installed TeraCopy (Windows 7, 64-bit). Every Clipboard.SetText() failed with a System.Runtime.InteropServices.COMException.

我在WPF 4.0和4.5中也有这个问题,因为我安装了TeraCopy (Windows 7, 64位)。每个Clipboard.SetText()在System.Runtime.InteropServices.COMException中失败。

My first solution was to uninstall TeraCopy - it worked, but I love this application, so I had to search for another solution to resolve that issue. The solution was to replace

我的第一个解决方案是卸载TeraCopy——它可以工作,但是我喜欢这个应用程序,所以我必须寻找另一个解决方案来解决这个问题。解决办法是替换

Clipboard.SetText("my string");

with

Clipboard.SetDataObject("my string");

#5


2  

I had the same problem with RichTextBox. The following code crashed randomly:

我对RichTextBox也有同样的问题。以下代码随机崩溃:

TextRange tr = new TextRange(rich.Document.ContentStart, rich.Document.ContentEnd);
System.Windows.Clipboard.SetDataObject(tr.Text);

It seems it's preferred to use System.Windows.Controls.RichTextBox.Copy

它似乎更喜欢使用System.Windows.Controls.RichTextBox.Copy

#6


2  

I had a problem to retrieve XAML data from the clipboard with .NET 4.6.1.

我在使用。net 4.6.1从剪贴板中检索XAML数据时遇到了一个问题。

Error message:

错误信息:

OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)))

OpenClipboard失败(HRESULT中的异常:0x800401D0 (CLIPBRD_E_CANT_OPEN))

I solved it as follows:

我解出如下:

int counter = 0;
object xamlClipData = null;

while (xamlClipData == null)
{
    try
    {
        if (counter > 10)
        {
            System.Windows.MessageBox.Show("No access to clipboard xaml data.");
            break;
        }

        counter++;

        if (System.Windows.Clipboard.GetDataObject().GetDataPresent(DataFormats.Xaml))
        {
            xamlClipData = System.Windows.Clipboard.GetData(DataFormats.Xaml);
        }
    }
    catch { }
}

#7


1  

I had the same problem in copying Excel cells to the clipboard and getting data from the clipboard as an HTML string.

我在将Excel单元格复制到剪贴板并作为HTML字符串从剪贴板获取数据时遇到了同样的问题。

You can use (while-try-catch) like in the below code.

您可以使用(while-try-catch),如下面的代码所示。

Excel.Application exap = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook wb = exap.Workbooks.Open(
                      sourceFileNameTextBox.Text,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                      Type.Missing, Type.Missing);
Excel.Sheets sh = wb.Worksheets;

bool clip = false;

// Copy Excel cells to clipboard
while (!clip)
{
    try
    {
        ws.Cells.get_Range(cells[0], cells[1]).Copy(Type.Missing);
        clip = true;
    }
    catch
    {
        clip = false;
    }
}

string b = "";

// Get Excel cells data from the clipboard as HTML

clip = false;
while(!clip)
{
    try
    {
        b = Clipboard.GetData(DataFormats.Html) as string;
        clip = true;
    }
    catch
    {
        clip = false;
    }
}

Also, you can have a counter in the while if the loop is more than 10 times or more, exception occur. I test its maximum counter is one and in one time loop clipboard work.

此外,如果循环次数超过10次或更多,则可以在while中使用计数器,这时会发生异常。我测试它的最大计数器是1,在一个时间循环剪贴板工作。

#8


0  

There's a DataGrid event/method signature for this exact purpose CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e) and is more reliable than Clipboard.SetDataObject(data) or Clipboard.SetText(data).

对于这个目的,有一个DataGrid事件/方法签名CopyingRowClipboardContent(对象发送方、datagrisleepclipboardeventargs e),它比剪贴板. setdataobject (data)或剪贴板. settext (data)更可靠。

Here's how to use it.

下面是如何使用它的方法。

Set "FullRow" at the SelectionUnit mode for dataGrid called myDataGrid

将“FullRow”设置为dataGrid的选择单元模式为myDataGrid

<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>

We have a method, myDataGrid_CopyingRowClipboardContent, that gets called for each row in the dataGrid to copy its contents to the clipboard. For example,for a datagrid with seven rows this is called seven times.

我们有一个方法,myDataGrid_CopyingRowClipboardContent,它为dataGrid中的每一行调用,将其内容复制到剪贴板。例如,对于有7行的datagrid,这被称为7次。

public int clipboardcalledcnt { get; set; } // CopyingRowClipboardContent invoked count
private void myDataGrid_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
    PathInfo cellpath = new PathInfo(); // A custom class to hold path information
    string path = string.Empty;

    DataGrid dgdataPaths = (DataGrid)sender;
    int rowcnt = dgdataPaths.SelectedItems.Count;

    cellpath = (PathInfo)e.Item;

    path = "Row #" + clipboardcalledcnt + " Len=" + cellpath.Length.ToString() + ", path=" + cellpath.Path;

    e.ClipboardRowContent.Clear();

    if (clipboardcalledcnt == 0) // Add header to clipboard paste
        e.ClipboardRowContent.Add(new DataGridClipboardCellContent("", null, "--- Clipboard Paste ---\t\t\n")); // \t cell divider, repeat (number of cells - 1)

    clipboardcalledcnt++;
    e.ClipboardRowContent.Add(new DataGridClipboardCellContent(path, null, path));

    if (clipboardcalledcnt == rowcnt)
        clipboardcalledcnt = 0;
}

#9


0  

Adding my answer from mentioned SO question for reference -

增加我从上述问题的回答作为参考-

Found this from Andrew Smith at http://blogs.infragistics.com/forums/t/35379.aspx -

在http://blogs.infragistics.com/forums/t/35379.aspx -上找到这篇文章

Technically only 1 process can open the clipboard so if another process has it opened the subsequent requests will fail until the first releases the clipboard. This was sort of handled in the WinForms Clipboard class where it would retry the set with a delay in between each try but the WPF clipboard class doesn't do this so if it fails on the first show the exception occurs. Even then we should probably catch the exception and raise the clipboard operation error if it still fails.

从技术上讲,只有一个进程可以打开剪贴板,所以如果另一个进程打开了剪贴板,那么在第一个进程释放剪贴板之前,后续的请求将会失败。这是在WinForms剪贴板类中处理的,在这个类中,每次尝试之间都会有一个延迟,但是WPF剪贴板类不会这么做,所以如果它在第一次出现异常时失败了。即使这样,如果异常仍然失败,我们也应该捕获异常并抛出剪贴板操作错误。

Same thing is explained and some ways to fix it are mentioned on this italian blog -

同样的事情被解释和一些解决它的方法被提到在这个意大利的博客上-

WPF DataGrid Clipboard BUG (?) & Work (Cached translation) (Orignal Link)

WPF DataGrid剪贴板BUG(?)和Work(缓存翻译)(Orignal链接)

Following MSDN forum thread suggests that this could be machine specific problem -

根据MSDN论坛提示,这可能是机器特有的问题

CLIPBRD_E_CANT_OPEN exception when copying to clipboard from a DataGrid

当从DataGrid复制到剪贴板时,CLIPBRD_E_CANT_OPEN异常。