I have a DataGrid backed by an ObservableCollection of objects in my ViewModel. I also have a context menu with a Copy entry which uses the default Copy command. I'd like to be able to copy data from the DataGrid, but when I click on the Copy menu item, WPF throws this exception:
OpenClipboard Failed (Exception from HRESULT: 0x800301D0 (CLIPBRD_E_CANT_OPEN))
ViewModel
public class ViewModel
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public ObservableCollection<Person> People { get; set; }
public ViewModel()
{
People = new ObservableCollection<Person>
{
new Person {FirstName = "Heir", LastName = "Band"},
new Person {FirstName = "Rose", LastName = "Anne"},
new Person {FirstName = "Tim", LastName = "Poral"}
};
}
}
XAML
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Path=People}">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy" Command="Copy" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
I've seen other descriptions of this exception. However:
More Information - 10/17/2019
I did some more digging after Abin Mathew posted his answer. While his answer is an excellent one, and it works--it doesn't use WPF Commanding, but rather uses RelayCommand. That's fine. This question doesn't specify that WPF Commanding must be used.
However, I still wanted to know why WPF Commanding Copy wasn't working for a DataGrid. In fact, it does work--it just depends on timing. If you run the exact code I posted above, but put breakpoints at System.Windows.Clipbard.Flush
and System.Windows.Controls.DataGrid.OnExecutedCopy
, and then click the run button each time the breakpoints are hit, the copy will succeed:
So in conclusion:
ApplicationCommands
like Cut & Copy only act on Selection
.if you are not able to select text like in TextBox then it will throw exception.
I am afraid that WPF
introduced a new Bug
for example like below
<TextBox>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Paste" Command="ApplicationCommands.Paste" />
<MenuItem Header="Copy" Command="ApplicationCommands.Copy" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
You can use copy on DataGrid
without selection by adding ICommand
and Binding
the Command
Like below
<MenuItem Header="Copy" Command="{Binding CopyCommand}" CommandParameter="{Binding}"
And the ViewModel will be
public ICommand CopyCommand => new RelayCommand<object>(Copy);
private static void Copy(object obj)
{
Clipboard.SetDataObject(((ViewModel)obj).People);
}
This will copy the collection of People
to the Clipboard
. If that is what you are trying to do.
Hope this helps.