Results 1 to 7 of 7

Thread: [RESOLVED] Dispose large number of controls quickly? or better manage resources?

  1. #1

    Thread Starter
    Hyperactive Member stepdragon's Avatar
    Join Date
    Aug 2011
    Location
    Cincinnati
    Posts
    288

    Resolved [RESOLVED] Dispose large number of controls quickly? or better manage resources?

    I'm working on a sort of file browser, where I use a flow layout control to show images. Each time I switch to a new screen I need to clear the control, and load new images (pictureboxes). I had been calling FlowLayoutPanel.Controls.Clear(), however I recently discovered that doesn't properly release resources (specifically, window handles) which causes an "error creating window handle" exception after about 10,000 pictures being loaded (which adds up after a few refreshes of the control).

    I tried a for each control loop to .dispose() each picturebox, but the loop takes much longer to process, and ends up making each control disappear individually, rather than as a group. Is there a way to dispose the entire control collection at once? or is there another option that I hadn't considered? (for example, a way to keep using controls.clear, and manage resources in the background?)

    Any ideas are very appreciated.

    If you're wrong, you'll learn. If I'm wrong, I'll learn. Try something new and go from there. That's how we improve.

    CodeBank: VB.Net - Simple Proper Image Scaling in Correct Aspect Ratio - Star Rating Control
    Useful Links: HOW TO USE CODE TAGS

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Dispose large number of controls quickly? or better manage resources?

    Quote Originally Posted by stepdragon View Post
    is there another option that I hadn't considered?
    Yes there is. Put the PictureBoxes into a temporary array or collection, Clear the FlowLayoutPanel and then loop through the temp list to Dispose everything.

    You could even run the loop on a secondary thread so that it doesn't hold up what you're doing in your UI. Of course, each PictureBox would have to actually be disposed on the UI thread but you can use an invocation for that. That way, the disposal of the PictureBoxes will only occur at times when the UI thread is not busy. I'll put together an example.

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Dispose large number of controls quickly? or better manage resources?

    Here's that example:
    vb.net Code:
    1. Private ReadOnly garbage As New ConcurrentQueue(Of Control)
    2.  
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4.     For Each child As Control In Me.FlowLayoutPanel1.Controls
    5.         Me.garbage.Enqueue(child)
    6.     Next
    7.  
    8.     Me.FlowLayoutPanel1.Controls.Clear()
    9.  
    10.     If Not Me.BackgroundWorker1.IsBusy Then
    11.         Me.BackgroundWorker1.RunWorkerAsync()
    12.     End If
    13. End Sub
    14.  
    15. Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    16.     Dim ctrl As Control = Nothing
    17.  
    18.     While Me.garbage.TryDequeue(ctrl)
    19.         Me.BackgroundWorker1.ReportProgress(0, ctrl)
    20.     End While
    21. End Sub
    22.  
    23. Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    24.     DirectCast(e.UserState, Control).Dispose()
    25. End Sub
    That's untested but I think it should work. The loop in the DoWork event handler just keeps on going while there are controls to dispose. Each time you clear, if the previous loop is still going then it continues, otherwise it's started again. Each call to ReportProgress will raise the ProgressChanged event and dispose a control, but it will wait until the UI thread is free if it's busy at the time. That adds some overhead but it's not anything that you will notice and it gives you the best of both worlds, i.e. get your controls disposed as quickly as possible without interrupting your UI.

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,039

    Re: Dispose large number of controls quickly? or better manage resources?

    While I like that approach, I wonder whether getting rid of the pictureboxes is even the best solution? You've already seen that disposing all the controls has a cost, as does creating them. You can't possibly be seeing hundreds of images, let alone thousands, so how many can you be seeing at any one time? I'd make that many controls and never dispose/create any more than that.

    Having said that, there are some advantages to a FlowLayoutPanel that could top a simpler design, when it comes to images. For example, I have a form that shows simple images in what amounts of a horizontal listbox. I figured out that I could only show three images at a time, so I put three pictureboxes on a panel along with a horizontal scrollbar. There is a list of images, and the pictureboxes are loaded from that list based on the position of the scrollbar. Every time I move the bar, the pictureboxes are re-loaded with the correct set of images for the new position of the bar. What I don't get with this design, and what you might get with a FlowLayoutPanel, is a partial image. When I move the scrollbar, I see three images. Those images can look like they are scrolling left or right as I move the scroll bar, but that's really just a trick of the mind, because all that is really happening is that the image is being loaded into the picturebox to the left or right. You can't scroll the bar such that you see two images, along with half of the image before those two and half of the image after those two, so you can't be 'part way' through an image. I don't know whether you get that effect with a FlowLayoutPanel or not, and I don't know whether it matters.

    Still, I could have dozens of images (not 10,000 by any stretch of the imagination), yet no matter how many images I have, there are only three picturebox controls. No more are created and none are destroyed.
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    Hyperactive Member stepdragon's Avatar
    Join Date
    Aug 2011
    Location
    Cincinnati
    Posts
    288

    Re: Dispose large number of controls quickly? or better manage resources?

    jmcilhinney, Thank you for taking the time to write out that example. I just got home and I'll be doing some testing with it soon. Do I not have to directly .dispose each item? Does the "Me.garbage.TryDequeue(ctrl)" actually release the resources? I'm sure I'll see something while testing, but since the error is something that only happens every couple thousand instances, it may be a bit harder to know exactly what's going on (from the perspective of someone who only just recently learned of that method)

    Shaggy Hiker, I understand where you're coming from. I was originally drawing the images myself and working from there, but I've implemented other parts of the interface where I depend on having unique controls that I can assign other properties to. I'm using the Tag property quite a bit, and unique contex menus. I'm also assigning them unique tooltips at generation. I know that can be done in a custom control, but it adds to the complexity, when I'm not trying to reinvent the wheel. In regards to only displaying so many controls at once, from a UI standpoint, there are generally about 50 images visible at one time (but they are dynamically sizable, so there could be many more at any one time, depending on user settings), I currently have approximately 680 items loading in each load, but there are times where many fewer are loaded at once. Part of the reason it operates this way is that its *kind of* like a file browser, where it loads anything it finds in the directories, and displays them. I would rather not index, or keep a database, because I'm constantly changing the locations of the files, and creating other files along side them, I don't want to run the risk of it losing sync and losing track of files. It may be a bit less efficient this way, but its not like I'm working on hundreds of thousands of files for a large company. This is a small tool which may be used for a couple thousand files total, and currently it only takes about 2 seconds to load nearly 700 files, that's more than efficient enough for its purpose.

    Another thing to consider is that I'm not loading large files, I'm actually dynamically generating and saving thumbnails the exact size of the preview images (if there isn't already a thumbnail available), so its not like I'm loading 700+ 2MB files, I'm only loading about 10-100kb files.

    I do appreciate the input though, looking at different ways to solve similar problems are always great at opening up creativity.

    If you're wrong, you'll learn. If I'm wrong, I'll learn. Try something new and go from there. That's how we improve.

    CodeBank: VB.Net - Simple Proper Image Scaling in Correct Aspect Ratio - Star Rating Control
    Useful Links: HOW TO USE CODE TAGS

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,344

    Re: Dispose large number of controls quickly? or better manage resources?

    Quote Originally Posted by stepdragon View Post
    jmcilhinney, Thank you for taking the time to write out that example. I just got home and I'll be doing some testing with it soon. Do I not have to directly .dispose each item? Does the "Me.garbage.TryDequeue(ctrl)" actually release the resources? I'm sure I'll see something while testing, but since the error is something that only happens every couple thousand instances, it may be a bit harder to know exactly what's going on (from the perspective of someone who only just recently learned of that method)
    Yes, you do have to dispose each control. That's why each control is being disposed in the ProgressChanged event handler. As is the point of the BackgroundWorker, DoWork is raised on a secondary thread and ProgressChanged is raised on the UI thread. That's why manipulating the queue can be done in the DoWork event handler while manipulating the controls, i.e. disposing them, must be done in the ProgressChanged event handler.

  7. #7

    Thread Starter
    Hyperactive Member stepdragon's Avatar
    Join Date
    Aug 2011
    Location
    Cincinnati
    Posts
    288

    Re: Dispose large number of controls quickly? or better manage resources?

    Now I understand. I was having a hard time understanding that you were passing the control back to the first thread using the report progress line. Then the directcast line is actually disposing the control itself. Sometimes I lose track of things when looking at something new. Thank you for taking the time to explain it again.

    I have it worked into the code and it seems to be working. I need to use the program for a bit to see if it still has any problems. But for now that seems like it did the trick. I'll let it run for a bit to be sure.

    If you're wrong, you'll learn. If I'm wrong, I'll learn. Try something new and go from there. That's how we improve.

    CodeBank: VB.Net - Simple Proper Image Scaling in Correct Aspect Ratio - Star Rating Control
    Useful Links: HOW TO USE CODE TAGS

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width