我有一个使用datagrid的WPF应用程序。该应用程序运行正常,直到我安装Visual Studio 2012和Blend + SketchFlow预览。现在,当我尝试使用 Ctrl + C (在任何应用程序中)将数据从网格复制到剪贴板时,我遇到以下异常:< / p>
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中引发此异常时剪贴板是否已锁定,因为我无法复制粘贴消息(必须将其写入文件)。此外,在复制过程开始之前,剪贴板未锁定。
如何解决这个问题?
答案 0 :(得分:81)
我们正在使用.NET 4.0。我们遇到了同样的问题,但在注销系统之后,代码过去常常工作了一段时间。
最后我们找到了替代方案。
如果要将字符串复制到剪贴板,
string data = "Copy This"
直到现在我使用以下方法
Clipboard.SetText(data);
一次又一次失败。然后我查看了其他可用于在 Clipboard Class 中设置剪贴板文本的方法,并尝试了以下方法:
Clipboard.SetDataObject(data);
它工作:)。我再也没遇到过这个问题。
答案 1 :(得分:68)
这是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;
}
答案 2 :(得分:6)
我也在应用程序中遇到问题,我将信息复制到剪贴板中,因为用户仔细阅读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()方法,其中包括重试计数和以毫秒为单位的重试延迟。这至少从我的代码中删除了一些重试 noise 。
你的里程可能会有所不同......加上可能会有副作用,我还没有偶然发现,所以如果有人知道它们,请发表评论。无论如何,我希望这证明对某人有用。
答案 3 :(得分:5)
我在WPF 4.0和4.5中也遇到过这个问题,因为我安装了 TeraCopy (Windows 7,64位)。每个Clipboard.SetText()都失败了,发生了System.Runtime.InteropServices.COMException。
我的第一个解决方案是卸载TeraCopy - 它有效,但我喜欢这个应用程序,所以我不得不寻找另一个解决方案来解决这个问题。解决方案是替换
Clipboard.SetText("my string");
与
Clipboard.SetDataObject("my string");
答案 4 :(得分:2)
我遇到了与RichTextBox相同的问题。以下代码随机崩溃:
TextRange tr = new TextRange(rich.Document.ContentStart, rich.Document.ContentEnd);
System.Windows.Clipboard.SetDataObject(tr.Text);
似乎首选使用 System.Windows.Controls.RichTextBox.Copy
答案 5 :(得分:2)
我在使用.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 { }
}
答案 6 :(得分:1)
我在将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
中设置一个计数器,异常发生。我测试它的最大计数器是一次和一次循环剪贴板工作。
答案 7 :(得分:1)
我终于找到了使用DataGrid实现的默认复制模式的解决方案。
以前的答案对我不起作用:
我终于找到了解决这个问题的新方法。您只需要清除剪贴板,然后再按“ Ctrl + C”即可。
因此,我在MainWindows.xaml文件资源中创建了新样式:
<Window.Resources>
<Style TargetType="DataGrid">
<EventSetter Event="PreviewKeyDown" Handler="DataGrid_PreviewKeyDown"/>
</Style>
</Window.Resources>
此样式用于处理我的应用程序的所有数据网格中的“ previewKeyDown”。 调用的方法如下:
private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.C && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
System.Windows.Forms.Clipboard.Clear();
}
}
之后,问题解决了。
答案 8 :(得分:0)
为此目的CopyingRowClipboardContent
(object sender
,DataGridRowClipboardEventArgs
e)提供了一个DataGrid事件/方法签名,并且比Clipboard.SetDataObject(data)
或{{1更可靠}}
以下是如何使用它。
设置&#34; FullRow&#34;在SelectionUnit模式下,dataGrid名为myDataGrid
Clipboard.SetText(data)
我们有一个方法<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>
,可以在dataGrid中调用每个行,将其内容复制到剪贴板。例如,对于具有七行的数据网格,这被称为七次。
myDataGrid_CopyingRowClipboardContent
答案 9 :(得分:0)
代码app.xaml
<Application.Resources>
<Style TargetType="DataGrid">
<EventSetter Event="PreviewKeyDown" Handler="DataGrid_PreviewKeyDown"/>
</Style>
</Application.Resources>
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.C && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
System.Windows.Forms.Clipboard.Clear();
}
}
}
}
我已经处理了这段代码。
答案 10 :(得分:0)
我为WPF Datagrid导出到Excel(CSV)写了一个扩展方法:
如果“ MyDatagrid”是您的数据网格的名称,请使用一行代码来调用自己的用户控件。
MyDatagrid.ExportToExcel(this);
并将此方法添加到扩展静态类中
#region DataGrid Extentions
public static void ExportToExcel(this DataGrid dg, UserControl owner, string filename = "")
{
try
{
dg.SelectionMode = DataGridSelectionMode.Extended;
dg.SelectAllCells();
Clipboard.Clear();
ApplicationCommands.Copy.Execute(null, dg);
var saveFileDialog = new SaveFileDialog
{
FileName = filename != "" ? filename : "gpmfca-exportedDocument",
DefaultExt = ".csv",
Filter = "Common Seprated Documents (.csv)|*.csv"
};
if (saveFileDialog.ShowDialog() == true)
{
var clip2 = Clipboard.GetText();
File.WriteAllText(saveFileDialog.FileName, clip2.Replace('\t', ','), Encoding.UTF8);
Process.Start(saveFileDialog.FileName);
}
dg.UnselectAllCells();
dg.SelectionMode = DataGridSelectionMode.Single;
}
catch (Exception ex)
{
owner.ShowMessageBox(ex.Message);
Clipboard.Clear();
}
}
#endregion
最后不要忘记
using Microsoft.Win32;
关于扩展类 并设置
ClipboardCopyMode="IncludeHeader"
针对您的数据网格。
答案 11 :(得分:-1)
这对我也有用。
从以下位置更改班级:
Clipboard.SetText("my string");
收件人:
Clipboard.SetDataObject("my string");