我有一个使用datagrid的WPF应用程序。该应用程序运行正常,直到我安装Visual Studio 2012和Blend + SketchFlow预览。现在,当我尝试使用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()
这真的很烦人。
我已经看到了一些对这个问题的引用here以及网络上的各个位置,没有真正的解决方案。
我可以验证在Visual Studio中引发此异常时剪贴板是否已锁定,因为我无法复制粘贴消息(必须将其写入文件)。此外,在复制过程开始之前未锁定剪贴板。
如何解决这个问题呢?
我们使用的是.NET 4.0。我们遇到了同样的问题,但是在注销系统之后,代码一段时间以来工作正常。
最后我们找到了替代方案。
如果要将字符串复制到剪贴板,
string data = "Copy This"
直到现在我使用以下方法
Clipboard.SetText(data);
它一次又一次地失败了。然后我查看了其他可用于在Clipboard Class中设置剪贴板文本的方法,并尝试了以下方法:
Clipboard.SetDataObject(data);
它工作:)。我再也没遇到过这个问题。
这是WPF剪贴板处理程序中的一个错误。您需要在Application.DispatcherUnhandledException事件中处理未处理的异常。
将此属性添加到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;
}
我也在应用程序中遇到问题,我将信息复制到剪贴板中,因为用户仔细阅读ListBox。复制的信息与所选项目相关,并允许他们将其(所述信息)粘贴到其他应用程序中以方便使用。偶尔我会在某些用户的系统上获得CLIPBRD_E_CANT_OPEN,但在其他用户的系统上则不会。
虽然我仍然无法修复争用,但我能够创建一些代码来查找导致争用的应用程序。我想至少分享这段代码,希望能帮到别人。我将添加我创建的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 Class),因为后者有一个4参数的SetDataObject()方法,其中包括重试计数和重试延迟(以毫秒为单位)。这至少从我的代码中删除了一些重试噪声。
你的里程可能会有所不同......加上可能会有副作用,我还没有偶然发现,所以如果有人知道它们,请评论。无论如何,我希望这证明对某人有用。
我在WPF 4.0和4.5中也遇到过这个问题,因为我安装了TeraCopy(Windows 7,64位)。每个Clipboard.SetText()都失败了System.Runtime.InteropServices.COMException。
我的第一个解决方案是卸载TeraCopy - 它有效,但我喜欢这个应用程序,所以我不得不寻找另一个解决方案来解决这个问题。解决方案是更换
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失败(HRESULT异常: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单元格复制到剪贴板并将数据从剪贴板作为HTML字符串时遇到了同样的问题。
您可以使用(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次或更多,您可以在while
中有一个计数器,异常发生。我测试它的最大计数器是一次性和一次性循环剪贴板工作。
这个确切的目的有一个DataGrid事件/方法签名CopyingRowClipboardContent
(object sender
,DataGridRowClipboardEventArgs
e),并且比Clipboard.SetDataObject(data)
或Clipboard.SetText(data)
更可靠。
这是如何使用它。
在SelectionUnit模式下为名为myDataGrid的dataGrid设置“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;
}
这对我也有用。
更改班级:
Clipboard.SetText("my string");
至:
Clipboard.SetDataObject("my string");