WPF DataGrid HTML clipboard data faulty
Description
The HTML fragment DataGrid puts into the clipboard is not accepted by other applications.
It appears that the fragment's offsets (StartHTML/EndHTML/StartFragment/EndFragment) do not match the content.
Reproduction Steps
Select all data in a DataGrid, copy and then paste to Excel.
Expected behavior
Excel (or other application) correctly accepts HTML data from DatGrid in clipboard.
Actual behavior
Application cannot interpret and paste HTML data copied from DataGrid but display error.
Regression?
Error was introduced with #8519.
Known Workarounds
- Derive DataGrid subclass and override OnExecutedCopy:
protected override void OnExecutedCopy(ExecutedRoutedEventArgs args)
{
base.OnExecutedCopy(args);
String htmlData = Clipboard.GetData(DataFormats.Html) as String;
htmlData = htmlData.Replace("\r\n\r\n", "\r\n");
Clipboard.SetData(DataFormats.Html, htmlData);
}
2. Manually select csv or other format when pasting data copied from DataGrid in other applications.
### Impact
High impact at my company's backoffice which uses copy/paste to Excel intensely. On a more general scale, probably low.
### Configuration
.Net 9 Win11
### Other information
The problem with the wrong offsets is a result of double CR/LFs between the header items in Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGridClipboardHelper.cs (lines 86-102) - remove those and everything works as before.
Cc @halgab
The origin code: https://github.com/dotnet/wpf/pull/8519/files#diff-1e969bd11b05c363a95985d0554e02082433d0d7a563a91c72392b6fe23a6d9cL18
The code in https://github.com/dotnet/wpf/pull/8519 : https://github.com/dotnet/wpf/pull/8519/files#diff-1e969bd11b05c363a95985d0554e02082433d0d7a563a91c72392b6fe23a6d9cR87-R116
@kniessen I try fix this issues in https://github.com/dotnet/wpf/pull/10477 .
So sorry for the bug. I thought I had fixed manually this automatic addition of 2 new lines instead if one everywhere but I guess this one slipped through...
@halgab could you please review https://github.com/dotnet/wpf/pull/10477 so we can get rid of this bug?
Sure. I've just commented on the PR per your request
@halgab Need I do any changes?
I don't think so. Thanks again for sorting out my mess
@halgab Don't worry. This is just a small problem.
I'm looking forward to when this is released.
I'm not sure if the original workaround:
var htmlData = Clipboard.GetData(DataFormats.Html) as string;
htmlData = htmlData.Replace("\r\n\r\n", "\r\n");
Clipboard.SetData(DataFormats.Html, htmlData);
always cleared other data formats, so pasting the string contents would no-op (ex into notepad), so I had to flip to this:
var frozenOLEClipboardData = Clipboard.GetDataObject();
var htmlData = frozenOLEClipboardData.GetData(DataFormats.Html) as string;
htmlData = htmlData.Replace("\r\n\r\n", "\r\n");
var clipboardData = new DataObject();
clipboardData.SetData(DataFormats.Text, frozenOLEClipboardData.GetData(DataFormats.Text));
clipboardData.SetData(DataFormats.UnicodeText, frozenOLEClipboardData.GetData(DataFormats.UnicodeText));
clipboardData.SetData(DataFormats.StringFormat, frozenOLEClipboardData.GetData(DataFormats.StringFormat));
clipboardData.SetData(DataFormats.CommaSeparatedValue, frozenOLEClipboardData.GetData(DataFormats.CommaSeparatedValue));
clipboardData.SetData(DataFormats.Html, htmlData);
Clipboard.SetDataObject(clipboardData, true);
to preserve the various clipboard formats/avoid getting an
System.InvalidOperationException with the message "Cannot SetData on a frozen OLE data object." (Happened when I tried overwriting the HTML on the object I got from Clipboard.GetDataObject()).
I was using PowerShell to see what was on the clipboard/help troubleshoot:
function Interrogate-Clipboard {
Add-Type -AssemblyName PresentationCore
$clipboard = [Windows.Clipboard]::GetDataObject()
if (-not $clipboard) {
Write-Host "Clipboard is empty or unavailable." -ForegroundColor Yellow
return
}
$dataFormats = $clipboard.GetFormats()
Write-Host "Data formats available on the clipboard:"
$dataFormats | ForEach-Object { Write-Host "- $_" }
foreach ($format in $dataFormats) {
try {
$data = $clipboard.GetData($format)
Write-Host "`nFormat: $format"
Write-Host "Data Type: $($data.GetType().FullName)"
Write-Host "Data Preview: $data"
} catch {
Write-Host "`nFormat: $format"
Write-Host "Error retrieving data: $_" -ForegroundColor Red
}
}
}
I could have sworn the original workaround kept the string/unicodetext/csv options on the clipboard, but maybe I just focused on excel and forgot to check the others.