How to fill a Listbox using multi thread in VB . NET?

Asked

Viewed 1,278 times

0

In a Windows Form Application I have a List Box that is filled from a list of IP’s. It works like this: there is a text file (config.eep) which contains a number of IP’s, by pressing a button to update the List Box, a loop is called by sending a ping to all IP’s of the file. Only the responding ones are inserted in the ListBox.

This is the code that updates the ListBox (lstListaIpAtiv):

Public Sub AtualizarListBox()
    'Atualiza a ListBox
    lstListaIpAtiv.Items.Clear()                                     'Limpa a ListBox
    Dim ping As Ping = New Ping
    Dim sLinhaAtual As String                                        'Linha corrente do arquivo de configuração
    Dim PingReply As PingReply
    Dim objLeitor As StreamReader
    Try
        objLeitor = File.OpenText(sCaminho)
    Catch ex As FileNotFoundException
        MsgBox("Arquivo de configuração não encontrado", MsgBoxStyle.OkOnly, "Aviso")
        Exit Sub
    End Try
    Me.Cursor = Cursors.WaitCursor                                     'Troca o cursor para o cursor de espera
    While objLeitor.Peek <> -1                                       'Looping nas Linhas, enquanto nao chegar ao fim do arquivo texto, ele não sai do loop
        sLinhaAtual = objLeitor.ReadLine()                           'Recupera a Linha do Arquivo e guarda na variavel do tipo string sLinhaAtual
        Try
            PingReply = ping.Send(sLinhaAtual)                       'Envia requisiçao de ping para IP da linha corrente
            If PingReply.Status = IPStatus.Success Then              'Verifica se houve resposta do IP em questão
                lstListaIpAtiv.Items.Add(sLinhaAtual)                'Grava a linha atual na list box caso essa responda ao Ping
            End If
        Catch ex As PingException
            Continue While
        End Try
    End While
    objLeitor.Close()                                                'Fecha o arquivo para escrita
    If (Not objLeitor Is Nothing) Then
        objLeitor.Dispose()
    End If
    Me.Cursor = Cursors.Arrow                                       'Retorna o cursor para o cursor normal
    lblNumMaqEnc.Text = lstListaIpAtiv.Items.Count()                'Conta quantos itens existem na ListBox e exibe na label
End Sub

The problem is that while this process does not end, the rest of the application is unavailable. I am trying to solve this with the creation of another thread to run this separate process while the thread primary continues with the execution of the rest of the application. I inserted the following code into the button which updates the ListBox (btnAtualizar):

 Dim AtualizaThread As New Thread(AddressOf AtualizarListBox)
 AtualizaThread.Start()

However, I get the following error:

Cross-thread Operation not Valid: Control 'lstListaIpAtiv' accessed from a thread other than the thread it was created on.

How to get around this?

1 answer

3


Changes to the interface can only be made by the thread running the interface itself.

The easiest way to ensure this happens is to place the following code at the beginning of your method:

Public Sub AtualizarListBox()
  If Me.InvokeRequired Then 
    Me.Invoke(New MethodInvoker(AddressOf AtualizarListBox)) 
  Else 
    ' seu código aqui
  End If 
End Sub

With this code, you will no longer be changing the ListBox directly, but yes passing a delegate to the form, asking it to run your code on its thread when it can.

However, if your code is slow, it will crash the interface thread until the update is complete, and the advantage of being a separate thread will be undone. In this case, you have two ways to go:

1. Separate a smaller method just for interface updates

For example, separate a method just to add an individual item to the Listbox, after you have already ping and have the result in hand.

2. Do not use threads

You don’t necessarily need to use threads. Simply place, within your loop, a call to Application.DoEvents(). Thus, you will release the UI thread to run the pending events (refresh the screen, process clicks, etc.), and thus eliminate the feeling that the application "froze".

Remembering that a mix of the two alternatives can also be done... You can use threads, keeping your algorithm as it is, just using the Invoke as I put it at the beginning of the answer, and add a Application.DoEvents() in the middle of your loop so the UI won’t freeze.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.