0
votes

I am having some problems lately with selecting ALL items(ONLY once!) from a listbox and adding them to a listview. I am using a backgroundworker to handle this task due to big content the listview will contain and to avoid GUI freezing while performing this task.

Ok, so here is the BackgroundWorker_ProgressChanged code :

  For Each item In ListBox3.SelectedItems

    listView1.Items.Add(ListBox3.SelectedItem, ImageList1.Images.Count - 1).SubItems.Add("Test")
      ListView1.Items("Test").SubItems.Add("")
       Next
      For Each item As ListViewItem In ListView1.SelectedItems

      Next
     End Sub

The above written code displays items in listview, but ONLY if the user selects a certain item from the Listbox3 and displays infinite times the selected items from the listbox, I want it display ONLY ONCE all selected items from the Listbox, in the Listview. I want to select ALL items automatically, without user intervention, I have tried several methods which have failed. Can someone please provide a solution to this issue ? Thanks.

2
Firstly, using a BackgroundWorker is rather pointless. Anything to do with the UI is inherently foreground work so moving data from one control to another is obviously foreground work. The ProgressChanged event handler is executed on the UI thread so using a BackgorundWorker` is completely pointless. - jmcilhinney
Also, what's the point of looping through any collection in the ListView, let alone the SelectedItems, when the idea is to add data to the ListView, not get data from it? This is an example of what happens when you write code without knowing what that code has to do. I'm not talking about just the end result but the steps to get there. You need to work out what the code has to do first, then implement those steps in code. If you had done that then there's no way you'd be looping through the SelectedItems of the ListView. - jmcilhinney
Ok, so I did it like that: For Each item In ListBox3.Items , however it shows them repeatedly each item. How do I display them only ONCE in the listview? Thanks. - Andrew Mickelson
+1 for everything jmcilhinney has said, but just want to add, The progress Changed even is actually in your UI thread. It is as indicated by the name used to update the UI to report progress. If you really want to use a background worker for this, you probably will need to pass in Listbox3.Items via the args parameter, then deal with the results in the worker complete handler - Hursey
As for why you're getting the items in your list view three times, based on the snippet you've given us, I see no obvious reason. Think we need to see a bit more of your code - Hursey

2 Answers

1
votes

I just tested and it seems that getting items from a ListBox on a secondary thread is not an issue, so I was wrong about that. Adding/setting items definitely would be though, so you'd need to add the items to the ListView on the UI thread. Here's some example code that just worked for me:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    BackgroundWorker1.RunWorkerAsync()
End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Dim outputItems As New List(Of ListViewItem)

    For Each inputItem As String In ListBox1.Items
        outputItems.Add(New ListViewItem(inputItem))
    Next

    e.Result = outputItems
End Sub

Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    Dim items = DirectCast(e.Result, List(Of ListViewItem))

    ListView1.Items.AddRange(items.ToArray())
End Sub
0
votes

The problem is all the screen redrawing. I am guessing you may not need a background worker if you limit the screen redraw.

I used a list for the ListViewItems since I don't know how many there will be. Had to convert the list to an array to use .AddRange.

As a matter of fact just the .BeginUpdate and .EndUpdate might speed things up enough to be acceptable.

I am not sure about the use of ImageList so you might have to play around with that.

Private Sub OpCode()
    Dim items = From itm In ListBox1.Items 'or ListBox1.SelectedItems
                Select CStr(itm)
    Dim lvItems As New List(Of ListViewItem)
    Dim imageIndex As Integer = ImageList1.Images.Count - 1
    For Each item In items
        Dim lvItem As New ListViewItem(item, imageIndex)
        lvItems.Add(lvItem)
    Next
    'ListView1.BeginUpdate()
    ListView1.Items.AddRange(lvItems.ToArray)
    'ListView1.EndUpdate()
End Sub