WPF DataGrid에서 붙여넣기 데이터를 복사할 때 OpenClipboard가 실패했습니다.
데이터 그리드를 사용하는 WPF 애플리케이션이 있습니다.Visual Studio 2012와 Blend+Sketch Flow 미리보기를 설치하기 전까지는 응용 프로그램이 정상적으로 작동했습니다.이제 +(어느 애플리케이션에서나)를 사용하여 그리드의 데이터를 클립보드에 복사하려고 하면 다음과 같은 예외가 발생합니다.
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()
이거 진짜 짜증나.
이 문제에 대한 몇 가지 언급은 여기와 웹상의 다양한 장소에서 볼 수 있지만 실질적인 해결책은 없습니다.
Visual Studio에서 이 예외가 발생하면 메시지를 복사하여 파일에 붙여넣을 수 없기 때문에 클립보드가 잠겨 있는지 확인할 수 있습니다.또한 복사 프로세스가 시작되기 전에 클립보드가 잠기지 않았습니다.
이 문제를 어떻게 해결하나요?
사용하고 있습니다.NET 4.0.같은 문제가 있었습니다만, 시스템 로그오프 후, 한동안 코드는 정상적으로 동작하고 있었습니다.
마침내 우리는 대안을 찾았다.
문자열을 클립보드에 복사하려면
string data = "Copy This"
지금까지 저는 다음과 같은 방법을 사용하고 있었습니다.
Clipboard.SetText(data);
그것은 계속해서 실패하고 있었다.그런 다음 클립보드 클래스에서 클립보드의 텍스트를 설정하는 데 사용할 수 있는 다른 방법을 살펴보고 다음을 시도했습니다.
Clipboard.SetDataObject(data);
효과가 있었습니다. :)다시는 그런 일이 없었지
WPF 클립보드핸들러의 버그입니다응용 프로그램에서 처리되지 않은 예외를 처리해야 합니다.Dispatcher Unhandled Exception 이벤트입니다.
이 Atribute를 에 추가합니다.Application
App.xaml의 요소
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이 표시되는 경우가 있지만 다른 사용자 시스템에서는 표시되지 않습니다.
경합을 수정하지 못했지만 경합을 일으키는 애플리케이션을 찾기 위한 코드를 만들 수 있었습니다.적어도 누군가에게 도움이 되길 바라면서 이 코드를 공유하고 싶습니다.범인의 Process 객체를 찾기 위해 작성한 사용문, 속성 및 메서드를 추가합니다.프로세스 항목에서 프로세스의 이름, PID, 기본 창 제목(있는 경우) 및 기타 유용한 데이터를 얻을 수 있습니다.코드 없이 추가한 코드 행은 다음과 같습니다(메모: 코드 조각 아래에 공유할 tidbit이 하나 더 있습니다).
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;
}
기타 메모: 코드를 조금 간략하게 한 다른 변경 사항은 시스템 사용에서 변환하는 것입니다.윈도클립보드를 시스템에 연결합니다.윈도Forms. 클립보드(시스템 참조).윈도Forms.Clipboard Class)는 리트라이 횟수와 리트라이 지연(밀리초 단위)을 포함한4 파라미터 SetDataObject() 메서드가 있기 때문입니다.이것으로 적어도 코드에서 재시도 노이즈의 일부가 제거되었습니다.
주행거리가 다를 수 있습니다.또, 아직 깨닫지 못한 부작용이 있을지도 모르기 때문에, 아는 사람이 있으면 코멘트를 주세요.어쨌든, 나는 이것이 누군가에게 도움이 되기를 바란다.
TeraCopy(Windows 7, 64비트)를 인스톨 했을 때부터, WPF 4.0 및 4.5에서도 이 문제가 발생했습니다.모든 클립보드SetText()가 시스템에서 실패했습니다.런타임상호 운용 서비스COMException.
첫 번째 솔루션은 Tera Copy를 제거하는 것이었습니다.이 어플리케이션이 마음에 들었기 때문에 이 문제를 해결하기 위해 다른 솔루션을 찾아야 했습니다.해결방법은,
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);
시스템을 사용하는 것이 더 좋을 것 같습니다.윈도컨트롤리치 텍스트 박스카피
를 사용하여 클립보드에서 XAML 데이터를 가져오는 데 문제가 발생했습니다.NET 4.6.1.
오류 메시지:
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 { }
}
DataGrid에 의해 구현된 기본 복사 모드를 사용할 수 있는 솔루션을 찾았습니다.
이전 답변은 효과가 없었습니다.
- 클립보드 사용.SetDataObject(데이터) 클립보드의 인스톨.SetText(데이터) --> 이 솔루션은 기대했던 솔루션과는 달랐습니다.복사기능을 실장하고 싶지 않았습니다.
- Dispatcher Unhandled Exception 처리 : 이유는 모르겠지만 동작하지 않았습니다.이 이벤트에 연결된 메서드가 호출되지 않았습니다.
나는 마침내 이 문제를 해결할 새로운 방법을 찾았다.Ctrl + C를 누르기 전에 클립보드를 지우기만 하면 됩니다.
그래서 Main Windows.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();
}
}
그 후, 문제는 해결되었다.
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;
}
}
'에도요.while
루프가 10회 이상일 경우 예외가 발생합니다.나는 그것의 최대 카운터를 1로 테스트하고 1회 반복 클립보드로 동작합니다.
코드 app.xaml
<Application.Resources>
<Style TargetType="DataGrid">
<EventSetter Event="PreviewKeyDown" Handler="DataGrid_PreviewKeyDown"/>
</Style>
</Application.Resources>
코드 파일 app.xaml.cs
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();
}
}
}
}
나는 이 코드를 처리했다.
을 위한 이벤트CopyingRowClipboardContent
)object sender
,DataGridRowClipboardEventArgs
.Clipboard.SetDataObject(data)
★★★★★★★★★★★★★★★★★」Clipboard.SetText(data)
.
사용법은 다음과 같습니다.
선택 항목에서 "FullRow"를 설정합니다.myDataGrid라는 dataGrid의 단위 모드
<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>
이 ★★★★★★★★★★★★★★★★★★★★★★★.myDataGrid_CopyingRowClipboardContent
dataGrid의 각 행에 대해 해당 내용을 클립보드에 복사하도록 호출됩니다.예를 들어, 행이 7개인 데이터그램의 경우 이를 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;
}
WPF 데이터그램을 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"
네 데이터그램을 위해.
언급URL : https://stackoverflow.com/questions/12769264/openclipboard-failed-when-copy-pasting-data-from-wpf-datagrid
'programing' 카테고리의 다른 글
조건의 Bash에서 "unary operator expected" 오류가 발생했습니다. (0) | 2023.04.17 |
---|---|
여러 열에서 최소값을 선택하는 가장 좋은 방법은 무엇입니까? (0) | 2023.04.17 |
Swift에서 ViewController를 해제하는 방법 (0) | 2023.04.17 |
텍스트 파일을 Excel 시트로 가져오는 중 (0) | 2023.04.17 |
C# EPplus OpenXML의 행 수 (0) | 2023.04.17 |