Locked Async CTP v3 - Form is not responding

  • sábado, 24 de diciembre de 2011 9:54
     
     

    Hi all,

    I played around with the new Async CTP v3 and try to list all files and its subdirectories asyncronously and show this progress by using a progress bar.

    Most of the code works fine, but just in the moment I list all entries my Windows form is not responding. What I'm doing wrong?

    Below my source code:

    Greetings

    Peter

    Imports System.IO
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Collections.ObjectModel
    Imports System.Net

    Public Class Form1

        Private Async Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

            'Clear all entries
            Me.ProgressBar1.Value = 0
            Me.ListBox1.Items.Clear()

            'Define progress
            Dim progress As New Progress(Of NumberEntries)

            'Define ProgressBar
            Me.ProgressBar1.Minimum = 0
            Me.ProgressBar1.Maximum = 100

            'Handler
            AddHandler progress.ProgressChanged, AddressOf ShowProgress

            'Call
            Await TaskEx.Run(Function() Auflistung("C:\windows", progress))

        End Sub

        Public Shared Function Auflistung(ByVal dir As String, ByVal progress As IProgress(Of NumberEntries)) As Task(Of String())

            Dim Direc As New DirectoryInfo(dir)
            Dim Files() As FileInfo
            Dim I As Long = 0

            Files = Direc.GetFiles("*.*", SearchOption.AllDirectories)

            For I = 0 To Files.GetUpperBound(0) - 1

                progress.Report(New NumberEntries With {.Count = (I / Files.GetUpperBound(0)), .Eintrag = Files(I).ToString})

            Next

        End Function

        Public Class NumberEntries

            Public Count As Long
            Public Eintrag As String

        End Class

        Public Sub ShowProgress(source As Object, e As Object)

            Me.ProgressBar1.Value = e.Count * 100
            Me.ListBox1.Items.Add(e.eintrag)

        End Sub

    End Class

Todas las respuestas

  • sábado, 24 de diciembre de 2011 14:35
     
     Respondida

    The reason your form is going (temporarily) unresponsive is because DirectoryInfo.GetFiles does all of the asynchronous work, and then you're doing all of the progress updates all at once. So your UI thread is flooded with updates.

    I recommend using DirectoryInfo.EnumerateFiles.

    P.S. Read through the Task-based Asynchronous Pattern document - it's in your VS Async CTP install directory under My Documents. It explains how to pattern your asynchronous methods so that they follow best practices and are unsurprising to other programmers.

            -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
      and How to Implement IDisposable and Finalizers: 3 Easy Rules
    Microsoft Certified Professional Developer

    How to get to Heaven according to the Bible
  • domingo, 25 de diciembre de 2011 16:22
     
     

    Hi Steve,

    thanks for your hint! Now my Windows form is still responding while all files are listed.  Below the whole source code including the changes.

    Merry Christmas,

    Peter

     

    Imports System.IO
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Collections.ObjectModel
    Imports System.Net

    Public Class Form1

        Private Async Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

            'Clear all entries
            Me.ProgressBar1.Value = 0
            Me.ListBox1.Items.Clear()

            'Define progress
            Dim progress As New Progress(Of NumberEntries)

            'Define ProgressBar
            Me.ProgressBar1.Minimum = 0
            Me.ProgressBar1.Maximum = 100

            'Handler
            AddHandler progress.ProgressChanged, AddressOf ShowProgress

            'Call
            Await TaskEx.Run(Function() ListInfos("C:\windows", progress))

        End Sub

        Public Shared Function ListInfos(ByVal dir As String, ByVal progress As IProgress(Of NumberEntries)) As Task(Of String())

            Dim Direc As New DirectoryInfo(dir)
            Dim I As Long = 0

            ' LINQ query for all files
            Dim files = From f In Direc.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)

            ' Show results
            For Each f As FileInfo In files

                I += 1
                progress.Report(New NumberEntries With {.Count = (I / files.Count), .Eintrag = f.ToString})

            Next

        End Function

        Public Class NumberEntries

            Public Count As Long
            Public Eintrag As String

        End Class

        Public Sub ShowProgress(source As Object, e As Object)

            Me.ProgressBar1.Value = e.Count * 100
            Me.ListBox1.Items.Add(e.eintrag)

        End Sub

    End Class