How To Load GridView Image from Direct URL in Thread

时间:2016-12-02 04:54:23

标签: vb.net winforms datagridview bitmap .net-3.5

I am working with Vb.NET Windows Form application and there was a grid on which images are loaded from memory, it was taking too much memory for a fraction of the time, if a low memory at low, sometimes program gets crashed. A solution was proposed to consume less memory by using direct memory stream and load the picture from URL.

But I am using a data grid view, I need to put all my processing in a thread so, it safely loads the pictures and program won't get stuck.

Below is the code for fetching images from URL and attaching it with GridView Cell, anyone guides me how to put into Thread.

Private Function GetBitmapFromLink(ByVal ImagePath As String) As Image
    Dim exp As Boolean = False
    Try
        Dim request As System.Net.WebRequest = System.Net.WebRequest.Create(ImagePath)
        Dim response As System.Net.WebResponse = request.GetResponse()
        Dim responseStream As System.IO.Stream = response.GetResponseStream()
        Dim Img As New Bitmap(responseStream)
        If Img IsNot Nothing Then
            Return Img
        End If
        Catch ex As Exception
            WriteToLog(ex)
    End Try
End Function

'Using here in loop
CType(dr.Cells("img1"), DataGridViewImageCell).Value = GetBitmapFromLink(ImagePath & dtImages.Rows(i)("ImageName"))

here is the comlete code:

Sub SetSource(ByVal dtImages As DataTable)
    Try
        Dim ImagePath As String = BaseUrl
        ImagePath = ImagePath.Replace("/a", "/p") & "vs/"
        LockWindowUpdate(Me.Handle)
        Try
            For Each dRow As DataRow In grdSent.Rows
                CType(dRow("img1"), DataGridViewImageCell).Value = Nothing
                CType(dRow("img2"), DataGridViewImageCell).Value = Nothing

            Next
        Catch ex As Exception

        End Try
        grdSent.Rows.Clear()

        Dim i As Integer = 0

        While (True)
            Dim drIndx As Integer
            Dim dr As DataGridViewRow

            If (dtImages.Rows.Count > i AndAlso dtImages.Rows(i)("image") IsNot DBNull.Value) Then

                drIndx = grdSent.Rows.Add()
                dr = grdSent.Rows(drIndx)

                Dim ms As New MemoryStream(CType(dtImages.Rows(i)("image"), Byte()))
                'CType(dr.Cells("img1"), DataGridViewImageCell).Value = Image.FromStream(ms)
                CType(dr.Cells("img1"), DataGridViewImageCell).Value = GetBitmapFromLink(ImagePath & dtImages.Rows(i)("ImageName"))
                dr.Cells("img1").Tag = dtImages.Rows(i)("id")
                ms.Close()
            Else
                Exit While
            End If
            i = i + 1

            If (dtImages.Rows.Count >= i) Then
                Try
                    Dim ms As New MemoryStream(CType(dtImages.Rows(i)("image"), Byte()))
                    'CType(dr.Cells("img2"), DataGridViewImageCell).Value = Image.FromStream(ms)
                    CType(dr.Cells("img2"), DataGridViewImageCell).Value = GetBitmapFromLink(ImagePath & dtImages.Rows(i)("ImageName"))
                    dr.Cells("img2").Tag = dtImages.Rows(i)("id")
                    ms.Close()
                Catch ex As Exception
                    CType(dr.Cells("img2"), DataGridViewImageCell).Value = My.Resources.WhiteDot
                    dr.Cells("img2").Tag = -1
                End Try
            Else
                Exit While
            End If
            i = i + 1
        End While
        If (grdSent.RowCount > 0) Then
            'If (grdSentiments.Rows(grdSent.RowCount - 1).Cells("img1").Value Is My.Resources.WhiteDot AndAlso grdSentiments.Rows(grdSent.RowCount - 1).Cells("img2").Value Is My.Resources.WhiteDot) Then
            '    grdSentiments.Rows.RemoveAt(grdSent.RowCount - 1)
            'End If
        End If
    Catch ex As Exception
        WriteToLog(ex)
    Finally
        LockWindowUpdate(0)
    End Try
End Sub

1 个答案:

答案 0 :(得分:2)

.NET 3.5

You can do it without changing your function. Just change the way you use it. For example:

Dim t As New Threading.Thread( _
    Sub()
        'You can start a loop here
        Dim url= "some url"                         'Get url from cell
        Dim image = GetBitmapFromLink(url)          'Get the image from url
        Me.Invoke(Sub()
                      ' Use the image here, for example:
                      Me.BackgroundImage = image    'Assign the image to cell
                  End Sub)
        'End loop here
    End Sub)
t.Start()

You can also consider using BackgroundWorker to run your time-consuming background tasks.

.NET 4.5 and higher

You can make it asynchronous using Async and Await:

Private Async Function GetBitmapFromLink(ByVal ImagePath As String) As Task(Of Image)
    Dim request As System.Net.WebRequest = System.Net.WebRequest.Create(ImagePath)
    Dim response As System.Net.WebResponse = Await request.GetResponseAsync()
    Dim responseStream As System.IO.Stream = response.GetResponseStream()
    Dim Img As New Bitmap(responseStream)
    Return Img
End Function

In above method, I used GetResponseAsync instead of GetResponse and called it using Await. I also stripped exception handling codes, you can add them again.

When using, the method should be called in a Async method. So if you want to use it in an event handler, for example in Load event of form, just add Async keyword to method handler like:

Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim url= "some url"
    Dim image = Await GetBitmapFromLink(url)
End Sub