Search code examples
vb.netwinformscontrolsdispose

vb.net dispose picturebox(es) and load them again


Hey all i have about 30 pictureboxes on my win form. It populates images everytime a new song gets played (think of it as "previous played list").

The pictureboxes look like so on the form (3 row of 10)

 ___  ___  ___  ___  ___  ___  ___  ___  ___  ___
 | |  | |  | |  | |  | |  | |  | |  | |  | |  | |
 ---  ---  ---  ---  ---  ---  ---  ---  ---  ---

 ___  ___  ___  ___  ___  ___  ___  ___  ___  ___
 | |  | |  | |  | |  | |  | |  | |  | |  | |  | |
 ---  ---  ---  ---  ---  ---  ---  ---  ---  ---

 ___  ___  ___  ___  ___  ___  ___  ___  ___  ___
 | |  | |  | |  | |  | |  | |  | |  | |  | |  | |
 ---  ---  ---  ---  ---  ---  ---  ---  ---  ---

This is how i am going about populating the pictureboxes on the form:

Private Sub getAlbumArt()
    ...lots of code in here

    If lblArtist.Text <> prevArtiest Then
        prevArtiest = lblArtist.Text
        AddHandler clearPrevPlayed.DoWork, AddressOf clearPrevPlayed_DoWork
        AddHandler clearPrevPlayed.RunWorkerCompleted, AddressOf clearPrevPlayed_RunWorkerCompleted

        clearPrevPlayed.RunWorkerAsync()
    End If
End Sub

Private Sub clearPrevPlayed_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
    For Each ctlControl In Me.Controls
        If TypeName(ctlControl) = "PictureBox" Then
            If InStr(ctlControl.name, "previous_") <> 0 Then
                ctlControl.Image = Nothing
                ctlControl.Controls.Clear()
                ctlControl.dispose()
            End If

            If InStr(ctlControl.name, "previousSong_") <> 0 Then
                ctlControl.Image = Nothing
                ctlControl.Controls.Clear()
                ctlControl.dispose()
            End If
        End If

        Application.DoEvents()
    Next ctlControl
End Sub

Private Sub clearPrevPlayed_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
    Call buildPrePlayed(lblArtist.Text)
End Sub

Private Sub buildPrePlayed(ByVal theArtest As String)
    Dim intX As Integer = 0
    Dim tmpNewImg(30) As PictureBox
    Dim tmpNewImgPlaceholder(30) As PictureBox
    Dim thePicsNames(30) As String
    Dim filePaths As Linq.IOrderedEnumerable(Of IO.FileInfo) = New DirectoryInfo(Application.StartupPath & "\cdcovers").GetFiles().OrderByDescending(Function(f As FileInfo) f.LastWriteTime)

    For Each fi As IO.FileInfo In filePaths
        If InStr(fi.Name, "_small") <> 0 And intX <= 30 Then
            thePicsNames(intX) = (fi.Name)
            intX += 1
        End If
    Next

    intX = 0

    Do Until intX = 30
        Dim newImgPlaceholder As New PictureBox
        Dim newImg As New PictureBox

        If thePicsNames(intX) <> "" Then
            newImgPlaceholder.Visible = True
            newImgPlaceholder.Image = My.Resources.cdPlaceHolder
        Else
            newImgPlaceholder.Image = My.Resources.BLANK
            newImgPlaceholder.Visible = False
        End If

        newImgPlaceholder.Size = New System.Drawing.Size(130, 130)
        newImgPlaceholder.BorderStyle = BorderStyle.None

        If intX = 0 Then
            newImgPlaceholder.Location = New Point(145, 600)
        ElseIf intX >= 1 And intX < 10 Then
            newImgPlaceholder.Location = New Point((tmpNewImgPlaceholder(intX - 1).Left + 160), 600)
        ElseIf intX = 10 Then
            newImgPlaceholder.Location = New Point(145, 760)
        ElseIf intX >= 10 And intX <= 19 Then
            newImgPlaceholder.Location = New Point((tmpNewImgPlaceholder(intX - 1).Left + 160), 760)
        ElseIf intX = 20 Then
            newImgPlaceholder.Location = New Point(145, 920)
        ElseIf intX >= 21 And intX <= 29 Then
            newImgPlaceholder.Location = New Point((tmpNewImgPlaceholder(intX - 1).Left + 160), 920)
        End If

        newImgPlaceholder.BackColor = Color.Transparent
        newImgPlaceholder.Name = "previous_" & intX

        If thePicsNames(intX) <> "" Then
            newImg.Visible = True
            newImg.Image = Image.FromFile(Application.StartupPath & "\cdcovers\" & thePicsNames(intX))
        Else
            newImg.Image = My.Resources.BLANK
            newImg.Visible = False
        End If

        newImg.Size = New System.Drawing.Size(120, 120)
        newImg.BorderStyle = BorderStyle.None

        If intX = 0 Then
            newImg.Location = New Point(150, 605)
        ElseIf intX >= 1 And intX < 10 Then
            newImg.Location = New Point((tmpNewImg(intX - 1).Left + 160), 605)
        ElseIf intX = 10 Then
            newImg.Location = New Point(150, 765)
        ElseIf intX >= 10 And intX <= 19 Then
            newImg.Location = New Point((tmpNewImg(intX - 1).Left + 160), 765)
        ElseIf intX = 20 Then
            newImg.Location = New Point(150, 925)
        ElseIf intX >= 21 And intX <= 29 Then
            newImg.Location = New Point((tmpNewImg(intX - 1).Left + 160), 925)
        End If

        newImg.BringToFront()
        newImg.Name = "previousSong_" & intX

        Me.Controls.Add(newImg)
        Me.Controls.Add(newImgPlaceholder)

        tmpNewImg(intX) = newImg
        tmpNewImgPlaceholder(intX) = newImgPlaceholder

        intX += 1
    Loop

    RemoveHandler clearPrevPlayed.DoWork, AddressOf clearPrevPlayed_DoWork
    RemoveHandler clearPrevPlayed.RunWorkerCompleted, AddressOf clearPrevPlayed_RunWorkerCompleted
End Sub

I have tried:

If InStr(ctlControl.name, "previous_") <> 0 Then
     ctlControl.Image = Nothing
     ctlControl.Controls.Clear()
     ctlControl.dispose()
End If

This does not seem to dispose the images as it loops... it doesn't even seem to find the pictureboxes on the form? When i stop my form and then start it again it populates the image just fine. Keep in mind that each image is grab as the song plays so its not due to it not having the image ready to place in the list - its an average of 3 minutes per song so thats plenty of time to grab the image and save it.

It seems to not be finding the picturebox controls that i programmable coded onto the form...

Any help would be great.. I'm sure its just something simple that i am missing...


Solution

  • Just keep a List(Of PictureBox) at Form level and add them to it as you create them. Now you can iterate over that list to get rid of them without having to "find" them again.

    So it could look like this instead:

    Private Previous As New List(Of PictureBox)
    
    Private Sub getAlbumArt()
    
        ' ...lots of code in here
    
        If lblArtist.Text <> prevArtiest Then
            prevArtiest = lblArtist.Text
    
            For Each pb As PictureBox In Previous
                pb.Dispose()
            Next
            Previous.Clear()
            Application.DoEvents()
    
            buildPrePlayed(lblArtist.Text)
        End If
    End Sub
    
    Private Sub buildPrePlayed(ByVal theArtest As String)
    
        ' ...lots of code in here
    
        intX = 0
        Do Until intX = 30
            Dim newImgPlaceholder As New PictureBox
            Dim newImg As New PictureBox
    
            Previous.Add(newImgPlaceholder)
            Previous.Add(newImg)
    
            ' ...lots of code in here
    
        Loop
    End Sub