0

i want to update a label while a foreach-loop.

The problem is: the program waits until the loop is done and then updates the label.

Is it possible to update the label during the foreach-loop?

Code:

Dim count as Integer = 0
For Each sFile as String in Files
    'ftp-code here, works well
    count = count+1
    progressbar1.value = count
    label1.text = "File " & count & " of 10 uploaded."
next

Thanks in advance

neverlucky
  • 35
  • 2
  • 10

3 Answers3

2

Label is not updated because UI thread is blocked while executing your foreach loop.
You can use async-await approach

Private Async Sub Button_Click(sender As Object, e As EventArgs) 
    Dim count as Integer = 0
    For Each sFile as String in Files
        'ftp-code here, works well
        count = count+1

        progressbar1.value = count
        label1.text = "File " & count & " of 10 uploaded."

        Await Task.Delay(100)
    Next
End Sub

Because you will work with Ftp connections, which is perfect candidate for using async-await.

The Await line will release UI thread which will update label with new value, and continue from that line after 100 milliseconds.

If you will use asynchronous code for ftp connection , then you don't need Task.Delay

Fabio
  • 31,528
  • 4
  • 33
  • 72
  • My program doesn't recognize `Task`. Are there any more things I should know? Maybe I just misunderstood what you mean. – neverlucky Jan 11 '17 at 12:26
0

You've already accepted an answer but just as an alternative a BackgroundWorker can also be used for something like this. In my case the FTP to get the original files happens very quickly so this snippet from the DoWork event is for downloading those files to a printer.

Dim cnt As Integer = docs.Count
Dim i As Integer = 1
For Each d As String In docs
    bgwTest.ReportProgress(BGW_State.S2_UpdStat, "Downloading file " & i.ToString & " of " & cnt.ToString)

    Dim fs As New IO.FileStream(My.Application.Info.DirectoryPath & "\labels\" & d, IO.FileMode.Open)
    Dim br As New IO.BinaryReader(fs)
    Dim bytes() As Byte = br.ReadBytes(CInt(br.BaseStream.Length))

    br.Close()
    fs.Close()
    For x = 0 To numPorts - 1
        If Port(x).IsOpen = True Then
            Port(x).Write(bytes, 0, bytes.Length)
        End If
    Next
    If bytes.Length > 2400 Then
        'these sleeps are because it is only 1-way comm to printer so I have no idea when printer is ready for next file
        System.Threading.Thread.Sleep(20000)
    Else
        System.Threading.Thread.Sleep(5000)
    End If

    i = i + 1
Next

In the ReportProgress event... (of course, you need to set WorkerReportsProgress property to True)

Private Sub bgwTest_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwTest.ProgressChanged

    Select Case e.ProgressPercentage
        'BGW_State is just a simple enum for the state,
        'which determines which UI controls I need to use.
        'Clearly I copy/pasted from a program that had 15 "states" :)
        Case BGW_State.S2_UpdStat
            Dim s As String = CType(e.UserState, String)
            lblStatus.Text = s
            lblStatus.Refresh()

        Case BGW_State.S15_ShowMessage
            Dim s As String = CType(e.UserState, String)
            MessageBox.Show(s)

    End Select

End Sub
topshot
  • 885
  • 6
  • 21
-1

Is it not enough to use Application.DoEvents()? This clears the build up and you should be able to see the text fields being updated very quickly.

  • [Is DoEvents Evil?](https://blog.codinghorror.com/is-doevents-evil/), also [Use of Application.DoEvents()](http://stackoverflow.com/a/5183623/1115360). – Andrew Morton Jan 11 '17 at 20:41