OpenClipboard ist beim Kopieren und Einfügen von Daten aus WPF DataGrid fehlgeschlagen

78

Ich habe eine WPF-Anwendung mit Datagrid. Die Anwendung funktionierte einwandfrei, bis ich Visual Studio 2012 und Blend + SketchFlow Preview installiert hatte. Wenn ich jetzt versuche, die Daten aus dem Raster mit Ctrl+ C(in einer beliebigen Anwendung) in die Zwischenablage zu kopieren , wird die folgende Ausnahme angezeigt:

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 wirklich nervig.

Ich habe hier und an verschiedenen Stellen im Internet einige Hinweise auf dieses Problem gesehen , 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?

Arsen Zahray
quelle
Das Problem tritt tatsächlich in Visual Studio 2019 auf, wenn Sie versuchen, die sln-Datei an der Stelle zu kopieren, an der beim Öffnen der IDE kürzlich geöffnete Projekte angezeigt werden.
JGFMK

Antworten:

98

Wir verwenden .NET 4.0. Wir hatten das gleiche Problem, aber nach dem Abmelden vom System funktionierte der Code einige Zeit einwandfrei.

Endlich haben wir die Alternative gefunden.

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

string data = "Copy This"

Bis jetzt habe ich die folgende Methode angewendet

Clipboard.SetText(data);

Es scheiterte immer wieder. Dann habe ich mir andere Methoden zum Festlegen von Text in der Zwischenablage in der Zwischenablageklasse angesehen und Folgendes versucht:

Clipboard.SetDataObject(data);

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

Kushdilip
quelle
5
Sehr gut. Ich benutze .NET 4.5 und das Problem ist immer noch da. Es scheint, dass dieser Fehler auftritt, wenn ich ein Element in der ListView erneut auswähle, aber ich habe keine Ahnung warum.
Alois Kraus
2
Ich benutze WPF und .NET 4.5 (nicht 4.5.1) und das Problem ist mit dieser Lösung weg! :-)
Marcel
1
SetDataObject hat hier gut funktioniert. SetText löst eine Ausnahme aus, die andere jedoch nicht. Vielen Dank!
Fabiano
Ich fand, dass dieser Aufruf gut mit mehreren Zwischenablage-Kopien von Datagrids funktioniert.
Segelfisch009
78

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

Fügen Sie dieses Attribut dem ApplicationElement 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;
}
Alex Wiese
quelle
5
Microsoft hat dies in .NET 4.5 behoben. Der Code ähnelt jetzt dem in den Windows Forms-Assemblys. Die Routinen der Zwischenablage haben eine Wiederholungszahl und eine Verzögerungszeit, anstatt nur fehlzuschlagen, sobald auf die Zwischenablage nicht zugegriffen werden kann.
Alex Wiese
2
Ich verwende .NET 4.0 und habe das gleiche Problem. Ich möchte die App.xaml-Dateien nicht berühren. Gibt es eine andere Lösung für dieses Problem?
Kushdilip
2
Warum möchten Sie die Dateien app.xaml nicht berühren? Sie können das Application.DispatcherUnhandledExceptionEreignis von einer anderen Stelle aus abonnieren, dies sollten Sie jedoch in Ihrer App-Klasse tun, wenn Ihre App geladen wird. Weitere Infos hier
Alex Wiese
6
@kushdilip Ja, diese Lösung ist in Ordnung, wenn Sie die Kontrolle über die Methode haben, mit der die Daten in der Zwischenablage festgelegt werden. Sie hilft jedoch nicht, wenn die Methode nicht in Ihrem Code enthalten ist. Zum Beispiel WPF-Steuerelemente und Steuerelemente von Drittanbietern. Wenn Sie die Fehlerbehebung nicht irgendwo in Ihrem Code implementieren, sind Sie in .NET 4.0 weiterhin davon betroffen.
Alex Wiese
6
SetText ist in 4.5 NICHT behoben, aber die Verwendung von SetDataObject scheint es zu beheben - JEDOCH: Mein Programm kopiert einen Ordnerpfad in die Zwischenablage. Es funktioniert in Ordnung, aber wenn ich die App im VS-Debugger starte und die .NET-Ausnahme aktiviere, passiert etwas Seltsames. Wenn ich beispielsweise in Notepad einfüge, funktioniert es einwandfrei, aber wenn ich in das Speicherortfeld von Windows Explorer einfüge, löst meine App eine COM-Ausnahme "Ungültige FORMATETC-Struktur (Ausnahme von HRESULT: 0x80040064 (DV_E_FORMATETC))" aus. Dies geschieht nur beim Debuggen mit Ausnahmebedingung, daher muss die Ausnahme irgendwo abgefangen und behandelt werden, aber es ist immer noch seltsam.
Dave
7

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, diese (diese Informationen) der Einfachheit halber 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 beheben 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 using- Anweisung, die Attribute und die Methode hinzufügen, die ich erstellt habe, um das Process- Objekt des Täters zu finden. Aus dem Prozesspunkt können Sie den Prozess Namen, PID, Hauptfenstertitel erhalten (wenn sie eine hat) und andere potenziell nützliche Daten. 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 zum 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;
    }

SONSTIGER HINWEIS: Eine andere Sache, die ich geändert habe, um meinen Code ein wenig zu vereinfachen, war die Konvertierung von System.Windows.Clipboard zu System.Windows.Forms.Clipboard (siehe System.Windows.Forms.Clipboard-Klasse ), da letztere eine 4- Klasse hat. Parameter SetDataObject () -Methode, die eine Wiederholungsanzahl und eine Wiederholungsverzögerung in Millisekunden enthält. Das zumindest einen Teil der Wiederholungs entfernt Rauschen von 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.

John
quelle
2
+1 für die Verwendung von System.Windows.Forms.Clipboard anstelle von System.Windows.Clipboard. danke
Dmase05
6

Ich hatte dieses Problem auch in WPF 4.0 und 4.5, seit ich TeraCopy (Windows 7, 64-Bit) installiert habe . Jede Zwischenablage.SetText () ist mit einer System.Runtime.InteropServices.COMException fehlgeschlagen.

Meine erste Lösung bestand darin, TeraCopy zu deinstallieren - es hat funktioniert, aber ich liebe diese Anwendung, daher 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");
pr0gg3r
quelle
Der Nachteil ist, dass die Daten beim Beenden der Anwendung aus der System-Zwischenablage gelöscht werden.
Hillin
1
Nicht, wenn Sie den zweiten Parameter auf true setzen, um nach dem Beenden der Anwendung Daten zu erhalten. Überprüfen Sie dies heraus: docs.microsoft.com/de-de/dotnet/api/…
pr0gg3r
2

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 bevorzugt zu sein, System.Windows.Controls.RichTextBox.Copy zu verwenden

AVEbrahimi
quelle
2

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 { }
}
Pollitzer
quelle
1

Ich hatte das gleiche Problem 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 whileAusnahme haben, wenn die Schleife mehr als zehnmal oder öfter ist. Ich teste seinen maximalen Zähler ist eine und in einer Zeitschleife Zwischenablage Arbeit.

Majid Gharaei
quelle
1

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 of Clipboard.SetText (data) -> Diese Lösung war nicht das, was ich erwartet hatte, ich wollte die Kopierfunktion nicht selbst implementieren.
  • Umgang mit 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 Dateiressourcen von MainWindows.xaml erstellt:

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

Dieser Stil wurde entwickelt, um den "Vorschau-Schlüssel" 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.

zlink17
quelle
0

Es gibt eine DataGrid-Ereignis- / Methodensignatur für genau diesen Zweck CopyingRowClipboardContent( object sender, DataGridRowClipboardEventArgse), die zuverlässiger als Clipboard.SetDataObject(data)oder ist Clipboard.SetText(data).

Hier erfahren Sie, wie Sie es verwenden.

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_CopyingRowClipboardContentdie für jede Zeile im dataGrid aufgerufen wird, um ihren Inhalt in die Zwischenablage zu kopieren. Bei einem Datagrid mit sieben Zeilen wird dies beispielsweise sieben Mal aufgerufen.

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

Code app.xaml

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

Codedatei 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();
            }
        }
    }
}

Ich habe mich mit diesem Code befasst.

user3115047
quelle
Bitte verbessern Sie Ihre Antwort, indem Sie sie besser als derzeit bearbeiten.
Kwoxer
0

Ich schreibe eine Erweiterungsmethode für den WPF-Datagrid-Export nach Excel (CSV):

Wenn "MyDatagrid" der Name Ihres Datagrid ist, verwenden Sie einen Zeilencode, um die eigene Benutzersteuerung aufzurufen.

MyDatagrid.ExportToExcel(this);

und fügen Sie diese Methode Ihrer statischen Erweiterungsklasse hinzu

#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

endlich nicht vergessen

using Microsoft.Win32;

auf Erweiterungsklasse und setzen

ClipboardCopyMode="IncludeHeader"

für Ihr Datagrid.

Jalal Maheri
quelle