Stacker
Stacker

Reputation: 29

Copying to clipboard and pasting events

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

Answers (1)

galakt
galakt

Reputation: 1439

Clipboard have standart formats:

  • CSV
  • Text
  • UnicodeText
  • System.String
  • HTML format

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

Related Questions