Richard C Richard C - 1 year ago 88 Question

Reading ListView from BackgroundWorker

I've tried doing some searchs but for the life of me I don't seem to be able to find the answer, or a suggested solution that works. Its probably my understanding, but hopefully asking my own question will give me an answer that works :o)

I have a Windows Form Application which consists of one item, ListView1

This ListView has items added to it from a file via a Drag / Drop which is done on the main UI Thread, no background worker, it consists of around 1500 rows.

I'm trying to get a background worker now to read this ListView, but I'm getting a Cross Threading error as ListView1 was not created on the same thread.

The error comes on the simplest of pieces of code, but I don't seem to be able to think of a way around it or implementing an invoke etc.

For i = 0 To Me.ListView1.Items.Count - 1

ValueStatement = ValueStatement & "(" & Me.ListView1.Items(i).SubItems(0).Text

If i = Me.ListView1.Items.Count - 1 Or counter = 500 Then
CommaTerminate = ";"
CommaTerminate = ","
End If

For y = 0 To Me.ListView1.Columns.Count - 1
ValueStatement = ValueStatement & "'" & Me.ListView1.Items(i).SubItems(y).Text & "'"
If y = Me.ListView1.Columns.Count - 1 Then
ValueStatement = ValueStatement & ")"
ValueStatement = ValueStatement & ","
End If

ValueStatement = ValueStatement & CommaTerminate & vbNewLine

If counter = 500 Then
SQLStatement = "INSERT INTO RAW_CLI_DATA_" & GlobalVariables.CDR_Company & " VALUES " & vbNewLine & ValueStatement
GenericDatabaseRequest(SQLStatement, "Loading RAW table with data..")
counter = 0
ValueStatement = ""
End If

counter = counter + 1

The error comes on the line
ValueStatement = ValueStatement & "(" & Me.ListView1.Items(i).SubItems(0).Text

Thanks for any help!

Answer Source

It sounds like you went down the wrong road early on. The ListView is supremely illsuited for database ops:

  • Everything is contained as String which means somewhere you will have code to convert it to other types
  • It does not support databinding which means you have to manually create rows...
  • ... then later iterate them to fish the data back out.

A DataGridView and DataTable would be simpler: When the user enters data into the control and it would be stored in the table and as the proper type. Setting the DataTable as the Datasource, the DataGridView would create the display (rows and columns) for you.

Some of the time it takes will be consumed by SQLite to perform the INSERT, but it also looks like you are spending a lot of time iterating and concatenating SQL. It's usually better to work with the data than the user's View of it anyway, so extract and pass the data to the worker.

First, suck the data out of the ListView into a String()() container:

Dim data = lv.Items.
    Cast(Of ListViewItem).
    Select(Function(s) New String() {s.SubItems(0).Text,

Then pass it to the BackGroundWorker:


The DoWork Event:

Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork

    ' unbox the data
    Dim dataToInsert = CType(e.Argument, String()())

    For n As Int32 = 0 To 2
        Console.WriteLine("[{0}], [{1}], [{2}]", dataToInsert(n)(0),

End Sub


[Patient Tempest], [Lorem ipsum dolor sit], [Swordfish]
[Sour Priestess], [hendrerit nibh tempor], [Perch]
[Frozen Justice], [Interdum ex felis], [Swordfish]

It correctly prints the random data I put into the LV.

This will allow you to process the ListView Data in the BackGroundWorker but it wont really save any time, it just keeps the UI unlocked. The real problem is elsewhere, probably in the DB ops.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download