从WPF DataGrid复制粘贴数据时,OpenClipboard失败
我有一个使用数据网格的WPF应用程序。 应用程序工作正常,直到我安装了Visual Studio 2012和Blend + SketchFlow预览。 现在,当我试图从Ctrl + C (在任何应用程序中)将网格中的数据复制到剪贴板中时,出现以下exception:
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()
这真的很烦人
我在这里和网上的不同位置都看到了这个问题的一些引用,但没有真正的解决scheme。
我可以validation剪贴板是否在Visual Studio中引发此exception时被locking,因为我无法复制粘贴消息(必须将其写入文件)。 另外,剪贴板在复制过程开始之前未被locking。
如何解决这个问题?
这是WPF剪贴板处理程序中的一个错误。 您需要处理Application.DispatcherUnhandledException事件中的未处理的exception。
将此属性添加到App.xaml中的Application
元素
DispatcherUnhandledException="Application_DispatcherUnhandledException"
将此代码添加到您的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; }
我们正在使用.NET 4.0。 我们遇到了同样的问题,但是在注销系统之后,代码在一段时间内工作正常。
最后我们find了替代scheme。
如果你想复制一个string到剪贴板,
string data = "Copy This"
直到现在我正在使用以下方法
Clipboard.SetText(data);
这是一次又一次的失败。 然后,我看了其他可用的方法来设置剪贴板类中的剪贴板中的文本,并尝试以下内容:
Clipboard.SetDataObject(data);
它的工作:)。 我再也没有这个问题。
我也在应用程序中遇到问题,在用户阅读ListBox时将信息复制到剪贴板中。 被复制的信息与select的项目相关,为了方便起见,它允许他们将其粘贴到其他应用程序中。 偶尔我会在某些用户的系统上获得CLIPBRD_E_CANT_OPEN,但在其他用户的系统上却不会。
虽然我仍然无法解决争用,但我能够创build一些代码来查找导致争用的应用程序。 我想至less分享这个代码,希望它可以帮助别人。 我将添加我创build的using语句,属性和方法来查找罪魁祸首的Process对象。 从Process项目中,您可以获得进程的名称,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; }
其他注意事项:我更改了一个简化我的代码的一点是从使用System.Windows.Clipboard转换到System.Windows.Forms.Clipboard (请参阅System.Windows.Forms.Clipboard类 ),因为后者有一个4-参数SetDataObject()方法,其中包括重试计数和重试延迟(毫秒)。 这至less从我的代码中删除了一些重试噪声 。
你的里程可能会有所不同…再加上可能有副作用,我还没有偶然发现,所以如果有人知道他们请评论。 无论如何,我希望这certificate对某人有用。
自从我安装TeraCopy (Windows 7,64位)后,我在WPF 4.0和4.5中也遇到了这个问题。 每个Clipboard.SetText()都失败了一个System.Runtime.InteropServices.COMException。
我的第一个解决scheme是卸载TeraCopy – 它的工作,但我喜欢这个应用程序,所以我不得不寻找另一个解决scheme来解决这个问题。 解决的办法是更换
Clipboard.SetText("my string");
同
Clipboard.SetDataObject("my string");
我有与RichTextBox相同的问题。 以下代码随机崩溃:
TextRange tr = new TextRange(rich.Document.ContentStart, rich.Document.ContentEnd); System.Windows.Clipboard.SetDataObject(tr.Text);
看来它最好使用System.Windows.Controls.RichTextBox.Copy
我有一个问题,从.NET 4.6.1剪贴板检索XAML数据。
错误信息:
OpenClipboard失败(从HRESULTexception:0x800401D0(CLIPBRD_E_CANT_OPEN)))
我解决它如下:
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 { } }
我有同样的问题在复制Excel单元格到剪贴板,并从剪贴板获取数据作为HTMLstring。
你可以像下面的代码一样使用(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; } }
此外,如果循环超过10次或更多,则可以有一个计数器,发生exception。 我testing它的最大计数器是一个一次循环剪贴板的工作。
有一个DataGrid事件/方法签名用于确切目的CopyingRowClipboardContent(对象发件人,DataGridRowClipboardEventArgs e),比Clipboard.SetDataObject(data)或Clipboard.SetText(data)更可靠。
以下是如何使用它。
在名为myDataGrid的dataGrid的SelectionUnit模式中设置“FullRow”
<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>
我们有一个方法,myDataGrid_CopyingRowClipboardContent,为dataGrid中的每一行调用它的内容复制到剪贴板。 例如,对于具有七行的数据网格,这被称为七次。
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; }