backgroundworker and listview

Zexor

Well-known member
Joined
Nov 28, 2008
Messages
520
Programming Experience
3-5
what would be the best way to loop thru all the info in a listview with a backgroundworker without getting cross thread? Doing the whole loop in the progresschanged? But that would just slows down the main thread. invoke? storing the listview in an array of lvItems and work with that?
 
Last edited:
A ListView is a control so the ONLY way to access the data it contains is on the UI thread. There's absolutely no point starting a BackgroundWorker if you're not going to do work in the DoWork event handler. The name should make it fairly obvious what that event is for. Likewise, the ProgressChanged event articulates in its name what it's for. If you want to process data in the DoWork event then that data must not be taken from or sent to the UI. It's a fairly simple rule and yet people continue to ignore or try to circumvent it. The process is simple and is always the same:

1. Get the data you need, if any, from the UI.
2. Start the BackgroundWorker by calling RunWorkerAsync and passing the data from step 1, if any, as an argument in a single object.
3. Do the background work in the DoWork event handler.
4. If you need to update the UI as you go then call ReportProgress, pass any data required as an argument in a single object and update the UI in the ProgressChanged event handler.
5. If you need to update the UI when you're done then pass any data required via the e.Result property and update the UI in the RunWorkerCompleted event handler.

What does this mean for you? Exactly what you'd expect: get the data out of the ListView on the UI thread first, then start the BackgroundWorker. That does NOT mean storing the ListViewItems in an array. The ListViewItems are part of the ListView, so accessing them in the DoWork event handler is still an issue. You need to extract the actual data from the ListViewItems into a list of some sort and pass that.
 
what would be the best way to loop thru all the info in a listview with a backgroundworker without getting cross thread? Doing the whole loop in the progresschanged? But that would just slows down the main thread. invoke? storing the listview in an array of lvItems and work with that?

You would need to pass in the form as an argument to the background worker. Then access the listview control using that reference.

VB.NET:
   [COLOR=Blue]Private[/COLOR] [COLOR=Blue]Sub[/COLOR] BGWorker_DoWork([COLOR=Blue]ByVal[/COLOR] sender [COLOR=Blue]As[/COLOR] [COLOR=Blue]Object[/COLOR], [COLOR=Blue]ByVal[/COLOR] e [COLOR=Blue]As[/COLOR] DoWorkEventArgs)

        [COLOR=Blue]Dim[/COLOR] Args [COLOR=Blue]As[/COLOR] [COLOR=Blue]Object[/COLOR]() = [COLOR=Blue]CType[/COLOR](e.Argument, [COLOR=Blue]Object[/COLOR]())

        [COLOR=Blue]Try[/COLOR]

            MyWorker.ParentForm = [COLOR=Blue]Me[/COLOR] 'Pass in your parent this is where your listview has been delcared

            [COLOR=Blue]If [/COLOR][COLOR=Blue]CType[/COLOR](Args(0), Actions) = Actions.Analyse Then
                    MyWorker.DoAnalyse()
            [COLOR=#0000ff]End If[/COLOR]


        [COLOR=Blue]Catch[/COLOR] ex [COLOR=Blue]As[/COLOR] InvalidAsynchronousStateException
            [COLOR=Blue]Throw[/COLOR] ex
        [COLOR=Blue]Catch[/COLOR] ex [COLOR=Blue]As[/COLOR] Exception
            [COLOR=Blue]Throw[/COLOR] ex
        [COLOR=Blue]End[/COLOR] [COLOR=Blue]Try[/COLOR]

    [COLOR=Blue]End[/COLOR] [COLOR=Blue]Sub[/COLOR]

Sorry for the edits

But you cannot change the listview within the background worker. You can however read from the listview.

If you need to modify the listview return New List(Of ListViewItem)

MyWorker BackgroundWorker
VB.NET:
    [COLOR=Blue]Friend[/COLOR] [COLOR=Blue]Sub[/COLOR] DoAnalyse([COLOR=Blue][/COLOR][COLOR=Blue][/COLOR][COLOR=Blue][/COLOR][COLOR=Blue][/COLOR][COLOR=#A31515][/COLOR][COLOR=Blue][/COLOR])
        [COLOR=Blue]Try[/COLOR]

            newListItems = [COLOR=Blue]New[/COLOR] List(Of ListViewItem)
            imageList = [COLOR=Blue]New[/COLOR] ImageList
            largeImageList = [COLOR=Blue]New[/COLOR] ImageList

            newListItems = FillListView(Me.ParentForm)[COLOR=#008000]'Do what you need to do to the current listview[/COLOR]

        [COLOR=Blue]Catch[/COLOR] ex [COLOR=Blue]As[/COLOR] Exception

            [COLOR=Blue]Throw[/COLOR] ex
        [COLOR=Blue]End[/COLOR] [COLOR=Blue]Try[/COLOR]

    [COLOR=Blue]End[/COLOR] [COLOR=Blue]Sub[/COLOR]


VB.NET:
    [COLOR=Blue]Private[/COLOR] [COLOR=Blue]Sub[/COLOR] BGWorker_RunWorkerCompleted([COLOR=Blue]ByVal[/COLOR] sender [COLOR=Blue]As[/COLOR] [COLOR=Blue]Object[/COLOR], [COLOR=Blue]ByVal[/COLOR] e [COLOR=Blue]As[/COLOR] RunWorkerCompletedEventArgs)
        [COLOR=Blue]Try[/COLOR]
                [COLOR=Blue]Me[/COLOR].MyListView.Items.Clear()
                [COLOR=Blue]Me[/COLOR].MyListView.Items.AddRange(MyWorker.NewListItems.ToArray)
                [COLOR=Blue]Me[/COLOR].MyListView.SmallImageList = MyWorker.imageList
                [COLOR=Blue]Me[/COLOR].MyListView.LargeImageList = MyWorker.largeImageList
                [COLOR=Blue]Me[/COLOR].MyListView.Update()

        [COLOR=Blue]Catch[/COLOR] ex [COLOR=Blue]As[/COLOR] Exception
             [COLOR=#0000ff]Throw ex[/COLOR]
        [COLOR=Blue]End[/COLOR] [COLOR=Blue]Try[/COLOR]
    [COLOR=Blue]End[/COLOR] [COLOR=Blue]Sub[/COLOR]

I hope this helps.
 
Last edited:
Back
Top