2016-12-02 39 views
1

我正在使用Vb.NET Windows窗體應用程序,並且存在從內存中加載圖像的網格,它佔用了太多內存的一小部分時間,如果低內存,有時程序崩潰。 提出了一種解決方案,通過使用直接內存流並從URL加載圖片來消耗更少的內存。如何從線程中的直接URL加載GridView圖像

但我正在使用數據網格視圖,我需要把我所有的處理放在一個線程中,因此,它安全地加載圖片,程序不會卡住。

以下是從URL獲取圖像並將其附加到GridView Cell的代碼,任何人都可以引導我如何投入線程。

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")) 

這裏是comlete代碼:

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 
+0

根據您的編輯,你的情況爲.NET 3.5這足以在另一個線程中調用'SetSource'。你可以在'Backgroundworker'的'DoWork'事件中做或者使用'Thread'來做到這一點。 Anywan,在你的方法中,你應該應用一些改變。在你訪問一個UI元素的每個地方,你應該使用'Invoke'來防止一個跨線程操作異常。 –

回答

2

.NET 3.5

你可以做到這一點不改變你的函數。只要改變你使用它的方式。例如:

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() 

您還可以考慮使用BackgroundWorker來運行耗時的後臺任務。

.NET 4.5和更高

你可以把它用異步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 

在上面的方法,我用GetResponseAsync代替GetResponse,並呼籲它使用Await。我也剝離了異常處理代碼,您可以再次添加它們。

使用時,應該在Async方法中調用該方法。所以,如果你想在Load事件的形式來使用它的事件處理程序,例如,只需添加Async關鍵字類似方法處理:

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 
+0

它支持.Net 4.0,堅果我的應用程序在.Net 3.5。 – DareDevil

+1

沒問題,這就是爲什麼你應該使用合適的標籤的問題。我將繼續爲.NET 4.0 +用戶提供答案,但也會爲.NET 3.5添加一些選項:) –

+0

O謝謝,它對4.0肯定有幫助。 – DareDevil