Sunday, June 17, 2007

Copy ListView to Clipboard in VB.NET, C#, and VB6

It is often useful to be able to copy the contents of a ListView to the Windows Clipboard. I have written a function for VB.NET, C#, and VB6 called CopyListViewToClipboard that will copy the contents of a ListView (in Details mode) to the Windows Clipboard. Additional functions are also available for a ListBox control here. The column headers will be the first row and the items in the listview will be the remaining rows. To make the copied data more compatible with applications like Excel, a tab character is placed between items in a row and a carriage return/linefeed is placed at the end of the row.

Here is an example ListView with some data in it:



Here is what is copied to the clipboard and then to Excel:




VB.NET:

Imports System.text

...


Public Sub CopyListViewToClipboard(ByVal lv As ListView)

Dim buffer As New StringBuilder

For i As Integer = 0 To lv.Columns.Count - 1
buffer.Append(lv.Columns(i).Text)
buffer.Append(vbTab)
Next

buffer.Append(vbCrLf)

For i As Integer = 0 To lv.Items.Count - 1
For j As Integer = 0 To lv.Columns.Count - 1
buffer.Append(lv.Items(i).SubItems(j).Text)
buffer.Append(vbTab)
Next
buffer.Append(vbCrLf)
Next

My.Computer.Clipboard.SetText(buffer.ToString)

End Sub


C#

using System.Text;

...


public void CopyListViewToClipboard(ListView lv)
{
StringBuilder buffer = new StringBuilder();

for (int i = 0; i < lv.Columns.Count; i++)
{
buffer.Append(lv.Columns[i].Text);
buffer.Append("\t");
}

buffer.Append("\n");

for (int i = 0; i < lv.Items.Count; i++)
{
for (int j = 0; j < lv.Columns.Count; j++)
{
buffer.Append(lv.Items[i].SubItems[j].Text);
buffer.Append("\t");
}

buffer.Append("\n");
}

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


VB6


Public Sub CopyListViewToClipboard(lv As ListView)

Dim buf As String
Dim i As Integer
Dim j As Integer

For i = 1 To lv.ColumnHeaders.count

buf = buf + lv.ColumnHeaders.Item(i).Text + vbTab

Next


buf = buf + vbCrLf

For i = 1 To lv.ListItems.count

buf = buf + lv.ListItems(i).Text

For j = 1 To lv.ColumnHeaders.count - 1
buf = buf + vbTab + lv.ListItems(i).SubItems(j)
Next

buf = buf + vbCrLf

Next

buf = buf + vbCrLf

Clipboard.Clear
Clipboard.SetText buf

End Sub

27 comments:

  1. Thanks. Just what I needed. Works very nicely!

    ReplyDelete
  2. There is no Clipboard.SetText in C#

    ReplyDelete
  3. There is a SetText method on the Clipboard object in C#. Please refer to the Microsoft Documentation below:

    http://msdn2.microsoft.com/en-us/library/ydby206k.aspx

    ReplyDelete
  4. Just what I needed - you might like to cache the columns count into a variable to save recounting for every row - don't know whether it's much of a performance issue.

    ReplyDelete
  5. thanx a lot! this worked perfectly!

    ReplyDelete
  6. Thanks! I learned something from this. BTW, for C# I had to change "\n" to Environment.NewLine to get it to paste properly.

    ReplyDelete
  7. Hi,
    Found this from Google. I was searching for clipboard copying from listview object. Very helpful. Thanks.

    ReplyDelete
  8. This is the sweetest sub ever! works perfectly.

    Almost immediately came up on google for terms "listview clipboard"

    Thanks!

    ReplyDelete
  9. Thanks for the method.

    Given I had a ListView that did not always have the same number of sub items as the column count, I had to update the code to handle that to prevent an index out of range exception:


    private void CopyListViewToClipboard(ListView lv)
    {
    StringBuilder buffer = new StringBuilder();

    foreach (ColumnHeader header in lv.Columns)
    {
    buffer.Append(header.Text);
    buffer.Append('\t');
    }
    buffer.Append(Environment.NewLine);

    foreach (ListViewItem item in lv.Items)
    {
    foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
    {
    buffer.Append(subItem.Text);
    buffer.Append('\t');
    }
    buffer.Append(Environment.NewLine);
    }

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

    ReplyDelete
  10. Add

    StringBuilder buffer = new StringBuilder();

    buffer.Append(" ");//Include this incase the ListView is empty

    Incase the ListView is empty, this will prevent the ClipBoard.SetText from throwing an exception.

    ReplyDelete
  11. Great Work.

    I found an error. If subitem has a space at the end or beginning, it will cause a problem with the tab (\ t) and the information is not copied correctly. The code would be as follows:

    private void CopyListViewToClipboard(ListView lv)
    {
    StringBuilder buffer = new StringBuilder();

    foreach (ColumnHeader header in lv.Columns)
    {
    buffer.Append(header.Text.Trim());
    buffer.Append('\t');
    }
    buffer.Append(Environment.NewLine);

    foreach (ListViewItem item in lv.Items)
    {
    foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
    {
    buffer.Append(subItem.Text.Trim());
    buffer.Append('\t');
    }
    buffer.Append(Environment.NewLine);
    }

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


    JAJG

    ReplyDelete
  12. Thanks, I found this right away and didn't have to waste time figuring it out... it works great. I added try/catches around it because it threw exceptions sometimes when there was no data in a column.

    ReplyDelete
  13. Thanks for the useful method. Love it. :-)

    ReplyDelete
  14. That was so nice at 12:37 w/ project due tommorow...ty. b

    ReplyDelete
  15. Thanks. Just what I needed.

    Very Good

    ReplyDelete
  16. Works like a charm! Thank you.

    ReplyDelete
  17. Works perfectly! That was very helpful.

    ReplyDelete
  18. That was just perfect! Thanks :)

    ReplyDelete
  19. Merci pour ce post qui marche très bien.

    ReplyDelete

Note: Only a member of this blog may post a comment.