Reputation: 29
I have a class User with a few fields of type string and int, I have a datagrid that displays those fields, I want the user to be able to select a row and press CTRL+C to copy the object the row represents to the clipboard, and when the user presses CTRL+V (when focus is on the datagrid) will add a new row to the datagrid. the code:
in xaml:
<DataGrid KeyDown="dgKeyDown" SelectionMode="Single" Name="dg1"
AutoGenerateColumns="False" CanUserAddRows="True"
CopyingRowClipboardContent="dg1Users_CopyingRowClipboardContent">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="Auto" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ID" Width="Auto" Binding="{Binding ID}" />
<DataGridTextColumn Header="Age" Width="Auto" Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>
dg1 Items Source is set to an observable collection of User objects:
dg1.ItemsSource = dg1Users;
and the copy and paste events:
private void dg1Users_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
User a = dg1.SelectedItem as User;
if (a != null)
{
Clipboard.Clear();
Clipboard.SetData("User1", a);
}
}
private void dgKeyDown(object sender, KeyEventArgs e)
{
User a = null;
if (e.Key == Key.V && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
if(Clipboard.ContainsData("User1"))
{
a = (User)Clipboard.GetData("User1");
dg1Users.Add(a);
}
}
}
It doesn't work, nothing happens, testing with a few print statements I found that when CTRL+V is pressed, the code in the 2nd if in dgKeyDown doesn't execute.
What am I doing wrong?
Note: I'm NOT using MVVM pattern.
Upvotes: 1
Views: 2668
Reputation: 1439
Clipboard have standart formats:
I prefer registr my custom format.
OK, 1) First set [Serializable] attribute
[Serializable]
public class User
{
public string Name { get; set; }
public string ID { get; set; }
public string Age { get; set; }
}
2) Then regist format, (i saved it to property for debug)
public DataFormat format { get; set; }
and
format = DataFormats.GetDataFormat(typeof(User).FullName);
3) Then you can save your object like this:
User a = dg1.SelectedItem as User;
if (a != null)
{
IDataObject dataObj = new DataObject();
dataObj.SetData(format.Name, a, true);
Clipboard.SetDataObject(dataObj, true);
}
4) You can retrive object like this:
User a = null;
IDataObject dataObj = Clipboard.GetDataObject();
if (dataObj != null && dataObj.GetDataPresent(format.Name))
{
a = dataObj.GetData(format.Name) as User;
dg1Users.Add(a);
}
5) Also we have here issue with events, which i dont know how resolve now
In your
private void dg1Users_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
}
you should prepare data for coping. For example, in e.ClipboardRowContent
will be string with data from selected row. So after g1Users_CopyingRowClipboardContent all what in e.ClipboardRowContent will be copy. That because your if(Clipboard.ContainsData("User1"))
false. Because in your clipboard at this moment stored string.
I changed code:
private void dgKeyDown(object sender, KeyEventArgs e)
{
User a = null;
if(e.Key == Key.V && Keyboard.Modifiers == ModifierKeys.Control)
{
IDataObject dataObj = Clipboard.GetDataObject();
if (dataObj !=null && dataObj.GetDataPresent(format.Name))
{
a = dataObj.GetData(format.Name) as User;
dg1Users.Add(a);
}
}
else if (e.Key == Key.B && Keyboard.Modifiers == ModifierKeys.Control)
{
User copingUser = dg1.SelectedItem as User;
if (copingUser != null)
{
IDataObject dataObj = new DataObject();
dataObj.SetData(format.Name, copingUser, true);
Clipboard.SetDataObject(dataObj, true);
}
}
}
and in this case i can copy-paste selected item
EDIT:
Because you dont use MVVM, so you dont use ApplicationCommands and etc.
So in your case you can set NotACommand for Copy build-in command like this.
After this, you can in my code change for else if (e.Key == Key.C && Keyboard.Modifiers == ModifierKeys.Control)
. I tested and it works as you want.
<DataGrid KeyDown="dgKeyDown" SelectionMode="Single" Name="dg1"
AutoGenerateColumns="False" CanUserAddRows="True">
<DataGrid.InputBindings>
<KeyBinding Key="C" Modifiers="Control" Command="ApplicationCommands.NotACommand"/>
</DataGrid.InputBindings>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="Auto" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ID" Width="Auto" Binding="{Binding ID}" />
<DataGridTextColumn Header="Age" Width="Auto" Binding="{Binding Age}"/>
</DataGrid.Columns>
</DataGrid>
Upvotes: 2