2016-12-02 6 views
1

Vb.NET Windowsフォームアプリケーションで作業していて、画像がメモリからロードされているグリッドがありました。低メモリ、プログラムがクラッシュすることがあります。 ダイレクトメモリストリームを使用してメモリを消費し、URLから画像をロードするというソリューションが提案されました。スレッド内の直接URLからGridViewイメージをロードする方法

私はデータグリッドビューを使用していますので、すべての処理をスレッドに入れておく必要があります。画像が安全にロードされ、プログラムが停止することはありません。

以下は、URLから画像を取得してGridView Cellに添付するためのコードです。だれかがスレッドに入れる方法を教えてくれます。あなたの機能を変更せずにそれを行うことができます

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

:ここ

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コードです。あなたがそれを使う方法を変えるだけです。たとえば:

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を使用してそれを呼ばれます。私も例外処理コードを取り除きました。それらを再度追加することができます。

使用する場合は、メソッドを非同期メソッドで呼び出す必要があります。ですから、フォームの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、Nutでサポートされています。私のアプリケーションは.Net 3.5です。 – DareDevil

+1

問題はないので、質問には適切なタグを使用する必要があります。私は.NET 4.0 +ユーザーのための答えを保ちますが、.NET 3.5のオプションもいくつか追加します:) –

+0

Oありがとう、確かに4.0に役立ちます。 – DareDevil

関連する問題