Reputation: 6893
I am trying to copy from one folder to another folder and following the msdn article I tried to implement an asnyc call on my WPF application. But I am not sure what I am doing wrong it blocks UI thread and I dont think this first sample is asnyc.
here is my code
Dim tasks = myImages.Select(Async Function(x)
Dim result As Image
Try
result = Await CopyImage(x, If(cts IsNot Nothing, cts.Token, Nothing))
Catch ex2 As Exception
End Try
ProgressValue += 1
CompletedText = ProgressValue.ToString() & " of " + MaxValue.ToString() & " images completed."
Return result
End Function)
Dim results = Await Task.WhenAll(tasks)
Public Async Function CopyImage(Image As Image, ct As CancellationToken) As Task(Of Image)
If ct.IsCancellationRequested Then
Return Nothing
End If
Await _mutex.WaitAsync()
Dim SourceMainDirectory As String = "\\Server\Folder1"
Dim DestinationMainDirectory As String = = "\\Server\Folder2"
Dim Path = Image.Path.Replace("/", "\")
Dim Data As String() = Path.Split("\")
Dim Folder As String
Dim ImageName As String
If Data IsNot Nothing AndAlso Data.Length > 1 Then
Folder = Data(0)
ImageName = Data(1)
End If
Dim ImgFullSource = SourceMainDirectory + Folder + "\" + ImageName
Dim ImgFullDest = DestinationMainDirectory + Folder + "\" + ImageName
Try
Using SourceStream As FileStream = File.Open(ImgFullSource, FileMode.Open)
Using DestinationStream As FileStream = File.Create(ImgFullDest)
Await SourceStream.CopyToAsync(DestinationStream, 81920, ct)
Return Image
End Using
End Using
Catch ex As OperationCanceledException
Return Nothing
Catch ex As Exception
Return Nothing
Finally
_mutex.Release()
End Try
Return Nothing
End Function
ProgressValue above is raised to update my progressbar Value. This Code works fine without blocking UI thread and perfectly updates progress asynchronously If I use myHttpClient.GetAsync method to verify same images on the web, for example
Dim tasks = myImages.Select(Async Function(x)
Dim result As Image
Try
result = Await testUrl_async_cancel(x, If(cts IsNot Nothing, cts.Token, Nothing))
Catch ex2 As Exception
End Try
ProgressValue += 1
CompletedText = ProgressValue.ToString() & " of " + MaxValue.ToString() & " images completed."
Return result
End Function)
Dim results = Await Task.WhenAll(tasks)
Async Function testUrl_async_cancel( ByVal myImage As Image, ByVal ct As CancellationToken) As Task(Of AEL)
If ct.IsCancellationRequested Then
Return Nothing
End If
Await _mutex.WaitAsync()
Dim myHttpClient As New HttpClient()
Dim myHttpResponse As HttpResponseMessage
myHttpClient.BaseAddress = New Uri(imageUrlD)
Try
myHttpResponse = Await myHttpClient.GetAsync(myImageUrl, ct)
Catch ex As OperationCanceledException
myHttpResponse = Nothing
Catch ex As Exception
myHttpResponse = Nothing
Finally
_mutex.Release()
End Try
If myHttpResponse IsNot Nothing AndAlso myHttpResponse.IsSuccessStatusCode Then
Return Nothing
Else
Return myImage
End If
End Function
So it should be something to do with the CopyImage function and respectively using the sourcestream what blocks the UI thread as all other code is the same. How can I make this code async that wont block the UI thread on WPF?
Upvotes: 0
Views: 408
Reputation: 6893
based on Stephen Cleary's answer. I changed the filestream read and write part as following and it works async without blocking the UI thread. I hope this helps anyone else looking for same solution.
last parameter True is the async parameter as Stephen mentioned.
Using SourceStream As FileStream = New FileStream(ImgFullSource, FileMode.Open, FileAccess.Read, FileShare.Read, 81920, True)
Using DestinationStream As FileStream = New FileStream(ImgFullDest, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 81920, True)
Await SourceStream.CopyToAsync(DestinationStream, 81920, ct)
Return Image
End Using
End Using
Upvotes: 1
Reputation: 456717
This behavior is due to an oddity in file streams. File.Open
and File.Create
can only return synchronous file streams.
To get a truly asynchronous file stream, you have to use the FileStream
constructor and either pass true
for the isAsync
parameter, or include the FileOptions.Asynchronous
flag in the options
parameter. You must call a constructor overload with either isAsync
or options
, or else the file stream will be synchronous.
Upvotes: 7