Search code examples
wpfasynchronousprogress-bardispatcherbegininvoke

WPF asynchronous invoke question


What's wrong in my code? It's not updating the TextBox and the ProgressBar while deleting files.

Imports System.Windows.Threading
Imports System.IO
Class MainWindow
    Private Sub bt_Click(ByVal sender As Object,
        ByVal e As RoutedEventArgs) Handles bt.Click

        Dim sb As New System.Text.StringBuilder
        Dim files = IO.Directory.EnumerateFiles(
         My.Computer.FileSystem.SpecialDirectories.Temp, "*.*",
         SearchOption.TopDirectoryOnly)

        Dim count = files.Count

        pb.Minimum = 0
        pb.Maximum = count

        For i = 0 To count - 1
            Dim f = files(i)

            Dispatcher.BeginInvoke(
             New Action(Of String, Integer)(
             Sub(str, int)
                 tb.SetValue(TextBox.TextProperty, str)
                 pb.SetValue(ProgressBar.ValueProperty, int)
             End Sub),
            DispatcherPriority.Send,
            f, i + 1)

            Try
                File.Delete(f)
            Catch ex As Exception
                sb.AppendLine(f)
            End Try

            Dim exceptions = sb.ToString
            Stop
        Next

    End Sub
End Class

Solution

  • I got this working with the BackgroundWorker object. This places your work in a background thread, with calls to update the UI going through the ProgressChanged event. I also used Invoke instead of BeginInvoke within the work loop, which forces the loop to wait for the UI to become updated before it proceeds.

    Imports System.ComponentModel
    Imports System.IO
    
    Class MainWindow
        Private WithEvents bw As New BackgroundWorker
    
        Private Sub Button1_Click(ByVal sender As System.Object,
                ByVal e As RoutedEventArgs) Handles btn.Click
            pb.Minimum = 0
            pb.Maximum = 100
            bw.WorkerReportsProgress = True
            bw.RunWorkerAsync()
        End Sub
    
        Private Sub bw_DoWork(ByVal sender As Object,
                 ByVal e As DoWorkEventArgs) Handles bw.DoWork
            Dim sb As New System.Text.StringBuilder
            Dim files = IO.Directory.EnumerateFiles(
             My.Computer.FileSystem.SpecialDirectories.Temp, "*.*",
             SearchOption.TopDirectoryOnly)
    
            Dim count = files.Count
            Me.Dispatcher.BeginInvoke(Sub()
                                          tb.Text = "SOMETHING ELSE"
                                      End Sub)
            For i = 0 To count - 1
                Dim f = files(i)
                Dim myI = i + 1
                Me.Dispatcher.Invoke(
                               Sub()
                                   bw.ReportProgress(CInt((myI / count) * 100), f)
                               End Sub)
    
                'Try 
                '    File.Delete(f) 
                'Catch ex As Exception 
                '    sb.AppendLine(f) 
                'End Try 
    
                Dim exceptions = sb.ToString
                'Stop 
            Next
        End Sub
    
    
        Private Sub bw_ProgressChanged(
                 ByVal sender As Object, 
                 ByVal e As ProgressChangedEventArgs) Handles bw.ProgressChanged
            Dim fString As String = TryCast(e.UserState, String)
            Me.Dispatcher.BeginInvoke(Sub()
                                          tb.Text = fString
                                      End Sub)
        End Sub
    End Class