webentwicklung-frage-antwort-db.com.de

OpenClipboard ist beim Kopieren von Daten aus WPF DataGrid fehlgeschlagen

Ich habe eine WPF-Anwendung mit Datagrid. Die Anwendung hat einwandfrei funktioniert, bis ich Visual Studio 2012 und Blend + SketchFlow Preview installiert habe. Nun, wenn ich versuche, die Daten aus dem Raster in die Zwischenablage zu kopieren Ctrl + C (in jeder Anwendung) erhalte ich die folgende Ausnahme:

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()

Das ist echt nervig.

Ich habe einige Hinweise auf dieses Problem gesehen hier und an verschiedenen Stellen im Web, ohne echte Lösung.

Ich kann überprüfen, ob die Zwischenablage gesperrt ist, wenn diese Ausnahme in Visual Studio ausgelöst wird, da ich die Nachricht nicht kopieren und einfügen konnte (musste sie in eine Datei schreiben). Außerdem wurde die Zwischenablage vor dem Start des Kopiervorgangs nicht gesperrt.

Wie kann man dieses Problem lösen?

63
Arsen Zahray

Wir verwenden .NET 4.0. Wir hatten das gleiche Problem, aber nachdem er sich vom System abgemeldet hatte, funktionierte der Code für einige Zeit einwandfrei.

Endlich haben wir die Alternative gefunden.

Wenn Sie eine Zeichenfolge in die Zwischenablage kopieren möchten,

string data = "Copy This"

Bisher habe ich die folgende Methode verwendet

Clipboard.SetText(data);

Es versagte immer wieder. Dann habe ich mir andere Methoden angesehen, um Text in der Zwischenablage in Clipboard Class zu setzen, und habe Folgendes versucht:

Clipboard.SetDataObject(data);

Und es hat funktioniert :). Ich hatte das Thema nie wieder.

79
kushdilip

Es ist ein Fehler im WPF Clipboard-Handler. Sie müssen die nicht behandelte Ausnahme im Application.DispatcherUnhandledException-Ereignis behandeln.

Fügen Sie dieses Attribut dem Application-Element in Ihrer App.xaml hinzu

DispatcherUnhandledException="Application_DispatcherUnhandledException"

Fügen Sie diesen Code Ihrer App.xaml.cs-Datei hinzu

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;
}
68
Alex Wiese

Ich hatte auch ein Problem in einer Anwendung, in der ich Informationen in die Zwischenablage kopiere, während Benutzer eine ListBox lesen. Die Informationen, die kopiert werden, beziehen sich auf das ausgewählte Element und ermöglichen es ihnen, es (die Informationen) zur Vereinfachung in andere Anwendungen einzufügen. Gelegentlich erhalte ich CLIPBRD_E_CANT_OPEN auf einigen Benutzersystemen, auf anderen jedoch nicht.

Obwohl ich den Konflikt immer noch nicht fix konnte, konnte ich Code erstellen, um die Anwendung zu finden, die den Konflikt verursacht. Ich möchte diesen Code zumindest in der Hoffnung teilen, dass er jemandem hilft. Ich werde die mit Anweisungen, Attributen und Methoden hinzufügen, die ich erstellt habe, um das Process Objekt von zu finden Täter. Aus dem Element Process können Sie den Namen des Prozesses, die PID, den Titel des Hauptfensters (falls vorhanden) und andere potenziell nützliche Daten abrufen. Hier sind die Codezeilen, die ich ohne den Code hinzugefügt habe, der sie aufruft. ( HINWEIS: Unter dem Code-Snippet habe ich noch einen Leckerbissen zu teilen):

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;
    }

ANDERER HINWEIS: Eine andere Sache, die ich geändert habe und die meinen Code ein wenig vereinfacht hat, war das Konvertieren von System.Windows.Clipboard bis System.Windows.Forms.Clipboard (siehe System.Windows.Forms.Clipboard-Klasse ), da letztere einen 4-Parameter hat SetDataObject () Methode, die einen Wiederholungszähler und eine Wiederholungsverzögerung in Millisekunden enthält. Dies entfernte zumindest einige der Wiederholungsversuche noise aus meinem Code.

Ihr Kilometerstand kann variieren ... und es kann Nebenwirkungen geben, auf die ich noch nicht gestoßen bin. Wenn also jemand davon weiß, kommentieren Sie dies bitte. Auf jeden Fall hoffe ich, dass sich dies für jemanden als nützlich erweist.

6
John

Ich hatte dieses Problem auch in WPF 4.0 und 4.5, seit ich TeraCopy (Windows 7, 64-Bit) installiert habe. Jeder Clipboard.SetText () schlug mit einer System.Runtime.InteropServices.COMException fehl.

Meine erste Lösung bestand darin, TeraCopy zu deinstallieren - es hat funktioniert, aber ich liebe diese Anwendung, also musste ich nach einer anderen Lösung suchen, um dieses Problem zu beheben. Die Lösung war zu ersetzen

Clipboard.SetText("my string");

mit

Clipboard.SetDataObject("my string");
5
pr0gg3r

Ich hatte das gleiche Problem mit RichTextBox. Der folgende Code stürzte zufällig ab:

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

Es scheint, dass es bevorzugt ist, System.Windows.Controls.RichTextBox.Copy zu verwenden

2
AVEbrahimi

Ich hatte ein Problem beim Abrufen von XAML-Daten aus der Zwischenablage mit .NET 4.6.1.

Fehlermeldung:

OpenClipboard fehlgeschlagen (Ausnahme von HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN)))

Ich habe es wie folgt gelöst:

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 { }
}
2
Pollitzer

Ich habe endlich eine Lösung gefunden, um den von DataGrid implementierten Standardkopiermodus zu verwenden.

Die vorherigen Antworten haben bei mir nicht funktioniert:

  • Verwenden von Clipboard.SetDataObject (Daten); insteed von Clipboard.SetText (data) -> Diese Lösung war nicht das, was ich erwartet hatte, ich wollte mir die Kopierfunktion nicht implementieren.
  • Behandlung von DispatcherUnhandledException: Ich weiß nicht warum, aber es hat bei mir nicht funktioniert. Die an dieses Ereignis angehängte Methode wurde nicht aufgerufen.

Ich habe endlich einen neuen Weg gefunden, um mit diesem Problem umzugehen. Sie müssen nur die Zwischenablage löschen, bevor Sie "Strg + C" drücken.

Also habe ich einen neuen Stil in den MainWindows.xaml-Dateiressourcen erstellt:

<Window.Resources>
    <Style TargetType="DataGrid">
        <EventSetter Event="PreviewKeyDown" Handler="DataGrid_PreviewKeyDown"/>
    </Style>
</Window.Resources>

Dieser Stil wurde erstellt, um "previewKeyDown" in allen Datagrids meiner Anwendung zu verarbeiten. Die aufgerufene Methode ist die folgende:

private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.C && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
    {
        System.Windows.Forms.Clipboard.Clear();
    }
}

Danach wurde das Problem gelöst.

1
zlink17

Das gleiche Problem hatte ich beim Kopieren von Excel-Zellen in die Zwischenablage und beim Abrufen von Daten aus der Zwischenablage als HTML-Zeichenfolge.

Sie können (while-try-catch) wie im folgenden Code verwenden.

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;
    }
}

Sie können auch einen Zähler in der Variablen while haben, wenn die Schleife mehr als 10-mal oder mehr ist und eine Ausnahme auftritt. Ich teste den maximalen Zähler auf Eins und in einer Zeitschleifen-Zwischenablage.

1
Majid gharaei

Hinzufügen meiner Antwort aus der erwähnten SO -Frage als Referenz -

Fand dies von Andrew Smith unter http://blogs.infragistics.com/forums/t/35379.aspx -

Technisch gesehen kann nur ein Prozess die Zwischenablage öffnen, wenn ein anderer Prozess hat es geöffnet, die nachfolgenden Anforderungen schlagen fehl, bis die Zuerst wird die Zwischenablage freigegeben. Dies wurde in den WinForms .__ behandelt. Clipboard-Klasse, bei der der Satz mit einer Verzögerung zwischen .__ wiederholt wird. Jeder Versuch, aber die WPF-Zwischenablageklasse führt dies nicht aus. Wenn dies unter .__ fehlschlägt. Bei der ersten Show tritt die Ausnahme auf. Selbst dann sollten wir wahrscheinlich fangen Sie die Ausnahme ab und lösen Sie den Fehler in der Zwischenablage aus, wenn sie scheitert immer noch.

In diesem italienischen Blog wird dasselbe erklärt und einige Möglichkeiten zur Behebung beschrieben:

WPF DataGrid Clipboard BUG (?) & Arbeit

Google Übersetzung

Der folgende Thread im MSDN-Forum legt nahe, dass dies ein maschinenspezifisches Problem sein könnte. -

CLIPBRD_E_CANT_OPEN Ausnahme beim Kopieren aus einer .__ in die Zwischenablage. DataGrid

Update:

Der Blog-Link scheint deaktiviert zu sein, aber eine zwischengespeicherte Version kann über diesen Link aufgerufen werden.

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

1
akjoshi

Für diesen genauen Zweck gibt es eine DataGrid-Ereigniss/Methodensignatur (CopyingRowClipboardContent (Objektsender, DataGridRowClipboardEventArgs)), die zuverlässiger ist als Clipboard.SetDataObject (Daten) oder Clipboard.SetText (Daten).

So verwenden Sie es.

Stellen Sie "FullRow" im SelectionUnit-Modus für dataGrid mit dem Namen myDataGrid ein

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

Wir haben eine Methode, myDataGrid_CopyingRowClipboardContent, die für each row im dataGrid aufgerufen wird, um ihren Inhalt in die Zwischenablage zu kopieren. Für ein Datagrid mit sieben Zeilen wird dies beispielsweise sieben Mal genannt.

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;
}
0
Markus