Listview with copy-paste
Asked Answered
E

5

14

Is there an easy way of adding copy-paste for a listview, or should I just switch to DataGridView instead?

My application is kinda like an address book, it contains emails, numbers etc where copy paste would be useful.

Enfleurage answered 12/6, 2010 at 18:23 Comment(0)
I
21

The example below handles the Ctrl-C as a copy to the clipboard command, and copies the second column's value from all the selected rows:

    private void resultsListView_KeyUp(object sender, KeyEventArgs e)
    {
        if (sender != resultsListView) return;

        if (e.Control && e.KeyCode == Keys.C)
            CopySelectedValuesToClipboard();
    }

    private void CopySelectedValuesToClipboard()
    {
        var builder = new StringBuilder();
        foreach (ListViewItem item in resultsListView.SelectedItems)
            builder.AppendLine(item.SubItems[1].Text);

        Clipboard.SetText(builder.ToString());
    }

Use item.Text for the first column, and item.SubItems[n].Text for other columns.

References:

  1. What is the KeyChar for Ctrl+C and Ctrl+V in C# to get the keys and proper event handler.
  2. Copy ListView to Clipboard in VB.NET, C#, and VB6 for full example of copying ListView to the Clipboard.
Irredentist answered 1/9, 2014 at 11:21 Comment(2)
Good solution, I just had to do that with the KeyDown event. KeyUp did not work, because when pressing the c it was auto-selecting the first entry in the ListBox which started with a c, rendering my multiselection to just a single one.Lampert
I was getting an invalid expection on builder.AppendLine(item.SubItems[1].Text); Instead, I had to use builder.AppendLine(item.Text);Suint
T
1

It's not very difficult to do manual copy and paste, just put in an event handler for KeyDown (or maybe it's KeyPress can't remember but fairly sure it's one of them) and check what key is pressed by looking at e.KeyCode and check if e.Control is true. If it's one of x, c or v just call Clipboard.SetText or Clipboard.GetText to write/read to/from the clipboard.
See here for the MSDN documentation of the Clipboard class.

You could add a context menu with Copy and Paste on to the ListView also to make it complete.

Through answered 12/6, 2010 at 19:31 Comment(2)
The problem with that is I only manage to copy the entire row, unless there is some neat tricks for selecting a cell.Enfleurage
@Zubirg: Yes, I forgot that you don't really have cells in a ListView, it might be easier to switch to a DataGridView. However, if you do want to stick with the ListView you could do something like handling Click and MouseDown events on it to calculate what subitem was clicked and then changing the BackColor of that subitem to make it look selected and then you could handle copy and paste for just that subitem. You'd have to make sure to set UseItemStyleForSubItems = false; on the Item though, otherwise the colours won't show on the subitems.Through
B
1

I've made it as method (depending on @brett's top answer), so just execute once on Form initialization: copyableListView(myListView) and it will do itself.

Code:

private void copyableListView(ListView listView)
{
    listView.KeyDown += (object sender, KeyEventArgs e) =>
    {
        if (!(sender is ListView)) return;

        if (e.Control && e.KeyCode == Keys.C)
        {
            var builder = new StringBuilder();
            foreach (ListViewItem item in (sender as ListView).SelectedItems)
                builder.AppendLine(item.Text + Environment.NewLine);
            Clipboard.SetText(builder.ToString());
        }
    };
}

Also, on form destroy, you should have method to remove all subscribed-events, i.e.

void myDeinit()
{
    myListView=null;
    myListView2=null;
    ...
}
Brochette answered 11/6, 2020 at 16:13 Comment(0)
S
0

My requirement was to add a button to copy a list of serial numbers to the clipboard. I added the button in the normal fashion and then added the following method:

private void btnClipboard_Click(object sender, EventArgs e)
{
    String clipText = string.Empty;
    foreach (ListViewItem item in lstSerials.Items)
    {
        clipText += item.SubItems[0].Text;
        clipText += Environment.NewLine;
    }
    if (!String.IsNullOrEmpty(clipText))
    {
        Clipboard.SetText(clipText);
    }
}
Stuyvesant answered 18/10, 2017 at 18:17 Comment(1)
Why did I get down-voted? This implementation works!Stuyvesant
M
0

Based on @Brett's answer, I wrote this method that copies the whole selected rows instead of just a single column (Especially good when FullRowSelect = true).

Two more improvements:

1.Ignore any newline - as ListView does.

2.Avoid an exception when no row is selected - Just clear the clipboard.

private void ListViewLogs_KeyDown(object sender, KeyEventArgs e)
{
    CopySelectedRowsToClipboard(listViewLogs, e);
}

private void CopySelectedRowsToClipboard(ListView listView, KeyEventArgs e)
{
    if (e.Control && e.KeyCode == Keys.C)
    {
        var builder = new StringBuilder();
        foreach (ListViewItem item in listView.SelectedItems)
        {
            var subItems = item.SubItems.Cast<ListViewItem.ListViewSubItem>()
                .Select(subItem => subItem.Text);
            builder.AppendLine(string.Join(", ", subItems).Replace(Environment.NewLine, ""));
        }

        if (builder.Length > 0)
            Clipboard.SetText(builder.ToString());
        else
            Clipboard.Clear();
    }
}
Midday answered 12/11, 2020 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.